{"slug": "your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the", "title": "Your GDScript arrays are slower than you think — I built a CLI that detects the pitfalls and benchmarks them", "summary": "A developer built gd-bench, a zero-dependency CLI that scans Godot .gd files for array-type performance pitfalls and generates runnable GDScript micro-benchmarks for each finding. The tool flags untyped arrays, typed arrays, packed arrays, and dictionaries used as sequential-key arrays, then emits headless benchmark scripts so developers can measure before rewriting. The developer says the scanner-plus-benchmark approach is meant to let the tool's advice be compared against the official docs' guidance in a single command.", "body_md": "\"Why is my enemy loop stuttering? I'm not even doing anything heavy here.\"\n\nEvery Godot tutorial tells you to just use arrays. Nobody tells you that an\n\nuntyped array holds Variants, that a sequential-key Dictionary is ~2x slower\n\nthan a plain Array, or that the official docs contradict themselves about\n\npacked arrays. This is about **gd-bench**, a CLI I built that scans your\n\n`.gd` files for array-type performance pitfalls and generates runnable Godot\n\nmicro-benchmarks for each one — with zero dependencies and no LLM anywhere.\n\n[https://github.com/sunnydachs/gd-bench](https://github.com/sunnydachs/gd-bench)\n\nPoint it at a Godot project. It scans every `.gd` file and reports where the\n\narray-type choice is costing you performance, then writes a runnable\n\nbenchmark script per finding so you can measure before you rewrite.\n\n```\npip install gd-bench\n\ngd-bench .              # scan the current project\ngd-bench . --gen-bench  # also generate Godot micro-benchmarks per finding\n```\n\nExample output (a small demo project, 7 files):\n\n``` js\ngame/main.gd:4  🐢 UNTYPED ARRAY\n    var inventory = []            # untyped array — Variant soup\n    ->\ngame/main.gd:5  🔧 TYPED ARRAY\n    var scores: Array[int] = []   # typed array — fine but Packed is faster\n    ->\ngame/main.gd:6  ✅ PACKED ARRAY\n    var points: PackedVector2Array = PackedVector2Array()  # already optimal\n    ->\n\nsummary: {\"typed_array\": 5, \"dict_as_array\": 2, \"untyped_array\": 1, \"packed_array\": 3}\n```\n\nIt reports 4 kinds of findings:\n\n`var x = [1, 2, 3]` holds Variants; slowest to iterate`Array[int]` gives compile-time checks but is still\nVariant-backed; `PackedInt32Array` is faster for the same element type`var d = {}` filled with sequential keys is ~2x slower\nand uses about half the memory again versus a plain Array\nA static type checker will never tell you which of these is actually slower\n\nin *your* loop — and the official docs can't agree either. Only a\n\nmeasurement can.\n\nThis was the core design decision. A linter could just say \"use\n\n`PackedInt32Array` here\" and be done. But I deliberately built it as\n\n**scanner + benchmark generator** instead. Three reasons:\n\nDeterministic work deserves deterministic tools.\n\nThe detail I obsessed over: the tool must never hand you a rewrite suggestion\n\nit hasn't equipped you to verify. So the rule is:\n\nThat single line (`書き換え前に必ず計測` / \"always measure before rewriting\")\n\nis what keeps the tool from becoming another \"just use X\" voice. The\n\ngenerated script is plain GDScript (`extends SceneTree`, runs headless) so\n\nyou can run it in CI or on a machine without the editor:\n\n```\ngodot --headless --script gd-bench-out/bench_gd_untyped_array_4.gd\n# gd-bench: untyped_array\n#   untyped_array: 8231 usec\n#   typed_array: 5120 usec\n#   ratio: 1.61x\n```\n\nNot a toy example — the detection patterns come from the same shapes real\n\nGodot projects and issues use:\n\n`DICT AS ARRAY` cases that were doing 1000 sequential-key inserts per frame\nThe real win wasn't just \"it works\" — it's that the tool's advice and the\n\ndocs' advice can be *compared* in one command, which is exactly what the\n\ngodot-docs issue is asking for.\n\n`var` lines, `{}` + indexed assignment); it does not catch arrays built\nthrough multi-line expressions or passed as literals into function calls.\nFrame time scales with your worst inner loop. Array-type choice is exactly\n\nthe class of problem where \"scanner + generated measurement\" earns its keep:\n\nthe advice is cheap to give, but only a benchmark tells you if it was true\n\nfor your code.\n\nThis is one in a series on the same principles — read-only, deterministic,\n\nzero-dependency CLIs that detect drift between what your code implies and\n\nwhat it does. Siblings: **dep-triage** (Dependabot PR cleanup),\n\n**pivot-diag** (Excel pivot audits), **doc-drift** (README code-example\n\ndrift), **plan-drift** (tracking plan ↔ implementation), **oas-drift**\n\n(OpenAPI spec ↔ code).\n\nFeedback, and especially *false-positive reports from your own Godot projects*, are the most useful thing you can give me — drop them in the repo", "url": "https://wpnews.pro/news/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the", "canonical_source": "https://dev.to/sunnydachs/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the-pitfalls-and-3ok3", "published_at": "2026-09-20 02:33:36+00:00", "updated_at": "2026-09-20 02:54:28.931251+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Godot", "gd-bench", "GDScript", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the", "markdown": "https://wpnews.pro/news/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the.md", "text": "https://wpnews.pro/news/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the.txt", "jsonld": "https://wpnews.pro/news/your-gdscript-arrays-are-slower-than-you-think-i-built-a-cli-that-detects-the.jsonld"}}