{"article":{"slug":"constructors-shouldnt-throw","title":"Constructors shouldn't throw","subtitle":null,"summary":"A short opinion piece arguing constructors should never throw, do async work, or perform side effects; parsing, connecting, and validation belong in factory methods or explicit lifecycle methods so object construction stays simple and predictable.","content_type":"opinion","language":"en","canonical_url":"https://t3.at/blog/2025-07-20-constructors-shouldnt-throw/","author":{"name":"Florian (Flonk)","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"T3 Blog","url":"https://t3.at/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Software Engineering","slug":"software-engineering","url":"https://listedarticles.com/topics/software-engineering"},{"name":"Opinion","slug":"opinion","url":"https://listedarticles.com/topics/opinion"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":397,"reading_minutes":2,"published_at":"2025-07-20T00:00:00.000Z","added_at":"2026-10-19T11:15:22.418Z","updated_at":"2026-10-19T11:15:22.418Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/constructors-shouldnt-throw","markdown_url":"https://listedarticles.com/articles/constructors-shouldnt-throw.md","example":false,"citation":"Florian (Flonk), T3 Blog. \"Constructors shouldn't throw.\" 20 Jul 2025. https://t3.at/blog/2025-07-20-constructors-shouldnt-throw/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://t3.at/blog/2025-07-20-constructors-shouldnt-throw/"},"body_markdown":"# Constructors shouldn't throw\n\nI mean this is nothing new but it bears repeating.\n\nConstructors should not throw exceptions. Nor should they do\nany asynchronous stuff, or really, perform any side effects at all.\n\n## But my Date constructor needs to parse a string!\n\nOkay I’m not in the business of writing Date libraries, but still,\nif you need to parse a string, write a parser. And then write\na factory method `Date.parse(string)` that uses that parser and\ncalls a private constructor.\n\n## But my Database constructor needs to connect to the database!\n\nHell it does. Turn your `Database` class into a state machine\nwith an `uninitialized` and a `connected` state.\nThen have a `Database.connect()` method that transitions the state\nfrom `uninitialized` to `connected`. Your unit tests will love it.\n\n## But my service needs to perform an API request!\n\nGood grief please don’t. A factory method will be your friend here,\nyou can do the fetch request in your factory and pass the value of\nthe resolved promise to the constructor.\n\n## But my constructor needs to log something!\n\nOkay that’s fine. I’m not that militant.\n\n## Why are you militant at all?\n\nThe C++ core guidelines say that “default constructors” should not\nthrow — those are the ones that take no arguments. In the C++\ncontext especially that makes sense because there we have RAII\nand you really don’t want a simple declaration like `Foo foo;`\nto throw an exception. If it does, you end up with half-constructed\nobjects and memory leaks and complicated cleanup. The C++\ncontainer classes assume `noexcept` constructors for this reason,\nbecause creating a list of size 20 calls your constructor 20 times,\nand the cleanup gets so much messier.\n\nWe don’t have to worry about this in JavaScript at all, but I think\neven there it’s good practice to avoid throwing exceptions in not\njust no-arg constructors, but all of them.\n\nBecause the semantics of a constructor is to bring an object\ninto a valid state and you don’t expect it to perform any\nfunctionality. Constructors should be simple and predictable.\n\nOften your objects are constructed in completely different\nplaces than where they are used so you really don’t want to\nknow about or deal with the implementation details of every class\nat construction time. It’s a separation of concerns thing.\n\nIf your objects have a complicated lifecycle you should design\ntheir APIs to reflect that.\n","body_html":"<h1 id=\"constructors-shouldn-t-throw\">Constructors shouldn&#39;t throw</h1>\n<p>I mean this is nothing new but it bears repeating.</p>\n<p>Constructors should not throw exceptions. Nor should they do\nany asynchronous stuff, or really, perform any side effects at all.</p>\n<h2 id=\"but-my-date-constructor-needs-to-parse-a-string\">But my Date constructor needs to parse a string!</h2>\n<p>Okay I’m not in the business of writing Date libraries, but still,\nif you need to parse a string, write a parser. And then write\na factory method <code>Date.parse(string)</code> that uses that parser and\ncalls a private constructor.</p>\n<h2 id=\"but-my-database-constructor-needs-to-connect-to-the-database\">But my Database constructor needs to connect to the database!</h2>\n<p>Hell it does. Turn your <code>Database</code> class into a state machine\nwith an <code>uninitialized</code> and a <code>connected</code> state.\nThen have a <code>Database.connect()</code> method that transitions the state\nfrom <code>uninitialized</code> to <code>connected</code>. Your unit tests will love it.</p>\n<h2 id=\"but-my-service-needs-to-perform-an-api-request\">But my service needs to perform an API request!</h2>\n<p>Good grief please don’t. A factory method will be your friend here,\nyou can do the fetch request in your factory and pass the value of\nthe resolved promise to the constructor.</p>\n<h2 id=\"but-my-constructor-needs-to-log-something\">But my constructor needs to log something!</h2>\n<p>Okay that’s fine. I’m not that militant.</p>\n<h2 id=\"why-are-you-militant-at-all\">Why are you militant at all?</h2>\n<p>The C++ core guidelines say that “default constructors” should not\nthrow — those are the ones that take no arguments. In the C++\ncontext especially that makes sense because there we have RAII\nand you really don’t want a simple declaration like <code>Foo foo;</code>\nto throw an exception. If it does, you end up with half-constructed\nobjects and memory leaks and complicated cleanup. The C++\ncontainer classes assume <code>noexcept</code> constructors for this reason,\nbecause creating a list of size 20 calls your constructor 20 times,\nand the cleanup gets so much messier.</p>\n<p>We don’t have to worry about this in JavaScript at all, but I think\neven there it’s good practice to avoid throwing exceptions in not\njust no-arg constructors, but all of them.</p>\n<p>Because the semantics of a constructor is to bring an object\ninto a valid state and you don’t expect it to perform any\nfunctionality. Constructors should be simple and predictable.</p>\n<p>Often your objects are constructed in completely different\nplaces than where they are used so you really don’t want to\nknow about or deal with the implementation details of every class\nat construction time. It’s a separation of concerns thing.</p>\n<p>If your objects have a complicated lifecycle you should design\ntheir APIs to reflect that.</p>","headings":[{"level":1,"text":"Constructors shouldn't throw","id":"constructors-shouldn-t-throw"},{"level":2,"text":"But my Date constructor needs to parse a string!","id":"but-my-date-constructor-needs-to-parse-a-string"},{"level":2,"text":"But my Database constructor needs to connect to the database!","id":"but-my-database-constructor-needs-to-connect-to-the-database"},{"level":2,"text":"But my service needs to perform an API request!","id":"but-my-service-needs-to-perform-an-api-request"},{"level":2,"text":"But my constructor needs to log something!","id":"but-my-constructor-needs-to-log-something"},{"level":2,"text":"Why are you militant at all?","id":"why-are-you-militant-at-all"}]}}