<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba" -->

---
title: GDScript: The Good, Bad, and Ugly Parts | daily.dev
description: A deep dive into GDScript's strengths and weaknesses, drawn from porting a significant TypeScript codebase to Godot. Praises GDScript's game-dev-specific...
canonical: https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: GDScript: The Good, Bad, and Ugly Parts | daily.dev
og:description: A deep dive into GDScript's strengths and weaknesses, drawn from porting a significant TypeScript codebase to Godot. Praises GDScript's game-dev-specific...
og:url: https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba
og:image: https://api.daily.dev/og/posts/uefLx4Oba.png
og:image:alt: GDScript: The Good, Bad, and Ugly Parts
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# GDScript: The Good, Bad, and Ugly Parts

**[Lobsters](https://daily.dev/sources/lobsters)** · 11 min read · 9 upvotes · 1 comments

## Summary

A deep dive into GDScript's strengths and weaknesses, drawn from porting a significant TypeScript codebase to Godot. Praises GDScript's game-dev-specific standard library, tight engine integration (preload, signals, editor annotations), and unique manual memory management with reference counting instead of garbage collection. Criticizes its underbaked static typing system—no proper function types, no union types, poor type narrowing, and awkward typed array casting. Also gripes about verbose syntax, missing spread/destructuring operators, no inner functions, and general friction around functional programming patterns, while noting Godot's lack of backward compatibility concerns leaves room for GDScript to improve.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://azhdarchid.com/gdscript-good-bad-ugly>

## Questions this post answers

### Why does mapping over a typed Array in GDScript throw a type error?

Array.map() in GDScript always returns an untyped array, even when called on a typed array like Array[int], so assigning its result directly to a typed array variable such as Array[String] triggers a type error. The workaround is to manually cast the result using the typed array constructor, e.g. Array(numbers.map(fn), TYPE_STRING, "", null), though this reportedly fails for inner classes.

_Developers hitting GDScript typing quirks while porting code can track language gotchas like this on daily.dev._

### Does GDScript use garbage collection for memory management?

No, GDScript has no garbage collector, which is unusual among high-level languages. It relies on manual memory management for scene tree nodes, which free themselves automatically when removed from the tree, and reference counting for other objects, with a weakref() function available to avoid cyclical reference issues.

_Comparing memory models across game-engine languages is easier when GDScript specifics are close at hand on daily.dev._

### Does GDScript support union types or discriminated unions like TypeScript?

No, GDScript has no union types or discriminated unions. Values that would be typed unions in TypeScript become generic Variant types in GDScript, with no practical way to recover more specific typing short of wrapping them in container classes, which introduces unnecessary heap allocations and doesn't fully solve the problem.

_Weighing GDScript against TypeScript for a Godot port gets easier with concrete comparisons like this on daily.dev._

## Community take

How the wider developer community reacted, aggregated from 2 discussions and 8 comments across hackernews, lobsters (as of 2026-09-15).

**TL;DR:** Discussion largely agrees GDScript has real design weaknesses, but debates whether these are unique flaws or shared with Python, while acknowledging its tight engine integration remains a genuine strength.

**Sentiment:** 15% positive · 45% mixed · 40% skeptical

**The case for**

- Some note GDScript's tight integration with the engine and complete docs make it genuinely useful despite its flaws.
- One commenter enjoyed the article's witty framing of how most game-dev languages weren't originally designed for games.

**The pushback**

- Several argue GDScript is a poorly designed language missing generics, optionals, and other established language features.
- One detailed rebuttal argues most of the criticized 'ugly' parts aren't actually shared with Python, which has better typing, destructuring, inner functions, and spread operators.
- One recalls GDScript historically lacked closures until recently, calling that a red flag.
- One notes that for any sizeable game, GDScript becomes a bottleneck, forcing teams toward C++ despite the added complexity.

**By community**

- hackernews (positive): Very light engagement, with the sole comment appreciating a witty line from the article.
- lobsters (mixed): Debate ranges from calling GDScript a poorly designed, underpowered language to defending its practical usefulness and engine integration.

**Hottest debate:** Whether GDScript's flaws stem from its Python-like design (and are thus shared with Python) or are unique shortcomings of GDScript itself.

**Highlights**

> > A lot of the "ugly" part in this article is the same as in Python, which GDScript draws inspiration from. Most of them are not in Python at all. Indentations and the callback pain is the only one which is. And Python has shorter anonymous functions but straight gives up on multiple statements in anonymous functions, though named functions have essentially no limitations, they're just more verbose. Python - has much better typing support, it's verbose and far from perfect but e.g. it supports generic callables and higher order functions just fine, if you `map` a `Callable[[int], str]` onto a `list[int]` you get an `Iterator[str]` (specifically a `map[str]`) - has destructuring assignment, though only positional - has inner functions - has no call/callv nonsense - has "a spread operator" (two of them in fact) - and they work for constructing collections, I can't really say that Python is great at immutable structures but it's not *that* bad (also it's been getting better, frozenset was added back in 3.6 and frozendict was finally accepted for 3.15, they're not *efficient* immutable collection but they're there)
> — [masklinn on lobsters · 1 points](https://lobste.rs/s/q5dgu6/gdscript_good_bad_ugly_parts#c_kyzcca)

> From a language design POV, GDScript is a poorly designed language. Putting aside the indentation -which is just a _preference_ -, It didn't integrate so far a lot good language design ideas from other languages. It looks just like a lazy copy of python. it is missing so many good things from anywhere else : generics, enums, optionals, etc. It doesn't mean it is not useful. its integration with the engine is good, the docs are quite complete and you can do a lot with that ugly little language. But at one point, for any sizeable game, it is the bottleneck for the engine. Yes, you can jump to c++ for that, but the complexity gap is quite large and in a gamedev team, you have less people that can write c++ than people that can script with gdscript.
> — [LBdN on lobsters · 1 points, 1 comments](https://lobste.rs/s/q5dgu6/gdscript_good_bad_ugly_parts#c_fzdauv)

> If I remember correctly, Godot started with Lua, and they found it worked well for what they wanted, except they needed it to be more class-oriented. IIRC up until the most recent version of GDscript it didn't even have *closures*, which always felt like a huge red flag to me. I'm very glad to hear that they're finally allowing other languages than GDscript.
> — [technomancy on lobsters · 2 points, 1 comments](https://lobste.rs/s/q5dgu6/gdscript_good_bad_ugly_parts#c_uqefno)

> A lot of the "ugly" part in this article is the same as in Python, which GDScript draws inspiration from. > GDScript is easy to learn with a syntax similar to Python where the code is indented rather than using lots of brackets and semicolons. -- https://gdscript.com/ I think the background is important. The author came from a TypeScript background and also likes to write functional-ish code, so they noticed things people coming from a Python background will probably just take for granted. Though using GDScript as a "quirky Python", one will also soon realise how underpowered this language is in other aspects.
> — [LesleyLai on lobsters · 5 points, 1 comments](https://lobste.rs/s/q5dgu6/gdscript_good_bad_ugly_parts#c_jfiemo)

**Source threads**

- [hackernews](https://news.ycombinator.com/item?id=49711304) · 2 points · 1 comments
- [lobsters](https://lobste.rs/s/q5dgu6/gdscript_good_bad_ugly_parts) · 24 points · 7 comments

## Community discussion

Top comments from developers on daily.dev.

**@starfallcodes** · 0 upvotes

> honestly i do not like gdscript at all, it feels akward to type in it.

## Similar posts on daily.dev

- [Experimenting with Godot](https://daily.dev/posts/experimenting-with-godot-gpgpvuaoc) · Matt Massicotte · 0 upvotes · 0 comments
- [New Godot Editor With Performance & UX Improvements](https://daily.dev/posts/new-godot-editor-with-performance-ux-improvements-w8g7eqavi) · 80 LEVEL · 19 upvotes · 2 comments

---

Tags: [#game-development](https://daily.dev/tags/game-development), [#godot](https://daily.dev/tags/godot), [#type-systems](https://daily.dev/tags/type-systems)

[View this post on daily.dev](https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"GDScript: The Good, Bad, and Ugly Parts","url":"https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba"},"datePublished":"2026-09-15T18:19:01.901Z","dateModified":"2026-09-15T21:19:35.219Z","description":"A deep dive into GDScript's strengths and weaknesses, drawn from porting a significant TypeScript codebase to Godot. Praises GDScript's game-dev-specific...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/0359c63cafd4a58b51de76f5a5f69d41?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/0359c63cafd4a58b51de76f5a5f69d41?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Lobsters","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Lobsters","logo":"https://media.daily.dev/image/upload/s--tl8v_Fku--/f_auto,t_logo/v1698841318/logos/lobste.jpg","url":"https://daily.dev/sources/lobsters"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":9},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"game-development,godot,type-systems","timeRequired":"PT11M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Lobsters","item":"https://daily.dev/sources/lobsters"},{"@type":"ListItem","position":3,"name":"GDScript: The Good, Bad, and Ugly Parts"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba","comment":[{"@type":"Comment","text":"honestly i do not like gdscript at all, it feels akward to type in it.","datePublished":"2026-09-19T06:29:47.261Z","url":"https://daily.dev/posts/uefLx4Oba#c-6k5Jpd5OV","author":{"@type":"Person","name":"Starfall :D","url":"https://daily.dev/starfallcodes","image":"https://media.daily.dev/image/upload/s--4xoTqFbk--/f_auto/v1786806197/avatars/avatar_ecPDW57nUVRidLxwsxruz?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/gdscript-the-good-bad-and-ugly-parts-ueflx4oba#faq","mainEntity":[{"@type":"Question","name":"Why does mapping over a typed Array in GDScript throw a type error?","acceptedAnswer":{"@type":"Answer","text":"Array.map() in GDScript always returns an untyped array, even when called on a typed array like Array[int], so assigning its result directly to a typed array variable such as Array[String] triggers a type error. The workaround is to manually cast the result using the typed array constructor, e.g. Array(numbers.map(fn), TYPE_STRING, \"\", null), though this reportedly fails for inner classes. Developers hitting GDScript typing quirks while porting code can track language gotchas like this on daily.dev."}},{"@type":"Question","name":"Does GDScript use garbage collection for memory management?","acceptedAnswer":{"@type":"Answer","text":"No, GDScript has no garbage collector, which is unusual among high-level languages. It relies on manual memory management for scene tree nodes, which free themselves automatically when removed from the tree, and reference counting for other objects, with a weakref() function available to avoid cyclical reference issues. Comparing memory models across game-engine languages is easier when GDScript specifics are close at hand on daily.dev."}},{"@type":"Question","name":"Does GDScript support union types or discriminated unions like TypeScript?","acceptedAnswer":{"@type":"Answer","text":"No, GDScript has no union types or discriminated unions. Values that would be typed unions in TypeScript become generic Variant types in GDScript, with no practical way to recover more specific typing short of wrapping them in container classes, which introduces unnecessary heap allocations and doesn't fully solve the problem. Weighing GDScript against TypeScript for a Godot port gets easier with concrete comparisons like this on daily.dev."}}]}
```

