Top
Best
New

Posted by yakkomajuri 11/3/2025

Why we migrated from Python to Node.js(blog.yakkomajuri.com)
229 points | 281 comments
srpablo 11/3/2025|
I'm really torn -- you and your engineers should be excited to work on your codebase. You should enter it and be like "yes, I've made good choices and this is a codebase I appreciate, and it has promise." If you have a set of storylines that make this migration appropriate, and its still early in the company that you can even do this in 3 days, then by all means, do it! And good luck. It'll never be cheaper to do it, and you are going to be "wearing" it for your company's lifetime.

But a part of me is reading this and thinking "friend... if PostHog was able to do what they're doing on the stack you're abandoning, do you think that stack is actually going to limit your scalability in any way that matters?" Like, you have the counterexample right there! Other companies are making the "technically worse" choice but making it work.

I love coding and I recognize that human beings are made of narratives, but this feels like 3 days you could have spent on customer needs or feature dev or marketing, and instead you rolled around in the code mud for a bit. It's fine to do that every now and then, and if this was a more radical jump (e.g. a BEAM language like Elixir or Gleam, or hell, even Golang, which has that preemptive scheduler + fast compiles/binary deploys + designed around a type system...) than I'd buy it more. And I'm not in your shoes so it's easy to armchair quarterback. But it smells a bit like getting in your head on technical narratives that are more fun to apply your creativity to, instead of the ones your company really needs.

xmprt 11/3/2025||
The author addresses that in the article. Python can scale but then developers would have to work with unintuitive async code. You can think of it as a form of tech debt - every single decision they make will take longer because they have to learn something new and double check if they're doing it the right way.
deanishe 11/4/2025||
> The author addresses that in the article. Python can scale but then developers would have to work with unintuitive async code

Python didn't cause their problems, Django did. They wanted async, but chose a framework that doesn't really support it. And they weren't even running it on an async app server.

Python didn't work for them because every subsequent choice they made was wrong.

xmprt 11/4/2025||
I think you're saying the same thing that I am. Python didn't work for them because they didn't use it correct and so accelerated the amount of tech debt they created. Posthog is using Django and they've scaled so clearly they've figured something out with using Python/Django with async but it probably isn't intuitive because neither you nor the author know of a good way to support it.
jaredklewis 11/4/2025|||
I’m surprised the article doesn’t make more of TypeScript.

From a technical perspective, I find both python and node.js to be pretty underwhelming. If I had to pick a shiny new thing it would probably be one of the usual suspects like Rust.

But last time I worked with Python (2022), types in python were pretty uninspiring. In 2022 typescript was already very powerful and it just keeps improving.

never_inline 11/4/2025||
Types in python are really good now.

It's the asyncio and all performance footguns which need to be fixed.

mmcromp 11/5/2025||
Whats "really good"? Pydantic? Mypy with dataclasses and built in typings? Is integration with Django okay? Genenily curious, not sarcastic. Im coming from from static typing and learning python ecosystem. Im still searching to make it work for me
never_inline 11/6/2025||
Pros:

Pydantic is good. Mypy and pyright are good enough for type checking real projects. I run mypy as pre commit. It takes time but it has saved me from real bugs.

The type system coupled with pydantic for validation is more expressive and ergonomic than java / go. But it's also lousy when working with people who don't have the type oriented thinking (especially juniors). You need to enforce people to type public signatures and enable strict linter settings.

Mixed:

Library wise, FastAPI ecosystem is type-first and works well. But old world ecosystems like django - I don't have first hand experience.

SQL alchemy seems to be getting better. But I wish something type-first similar to sqlc or room or Micronaut Data JDBC existed for python, where I could just use pydantic validated DTOs and use query builder, rather than dealing with SQLAlchemy's proxy objects. It's workable though. I would suggest keeping SQLA objects in only the layer that touches the DB and convert them to pydantic models at the boundary.

Library support is hit or miss. In common web dev, I get good typings as long as I stick to popular and "boring" libraries. Sometimes I have to look at docstring and use typing.cast to return types.

Cons:

new type checking solutions like pyrefly aren't there yet for my use cases. Ruff is good as linter and VSCode extension.

IDE extensions and mypy still miss some bugs which should never happen in typed languages. ESP with coroutines. (I wish there was a way to make it an error, to call coroutines without await, unless submitting them to a asyncio.run or gather etc.., dart has very good async linting in comparison).

Writing a: dict[tuple[str, str, str], int] = {} is no fun. But it guarantees if I use a wrong type of key down in the function, I will get a red squiggle.

shirokuma 11/4/2025|||
It's insane to me how making the technically worse choice is okay to you because some company out there is "making it work"

Also what could you do in 3 mere days that would pay off more than having the code in a language that the team is much more efficient with, one which doesn't need hacks to "make it work"?

It would save you several days on features forever, compared to doing one thing for just 3 days.

zelphirkalt 11/5/2025||
Basically, you have said it: It is about what the team is knowledgeable about.

In my book Nodejs doesn't belong on the server, but that's the choice they made. Python at least is thought out as a backend language, but can also be criticized for many aspects. If a team is more knowledgeable about modern languages, of course there are many technically probably better choices than both Nodejs or Python.

vips7L 11/4/2025|||
I don’t think I’ve ever worked in a codebase I’ve been excited about. I didn’t know those existed.
riffraff 11/4/2025||
They exist in the brief moment between a project start and when deadlines start to loom ;)

More seriously, I've worked on codebases I found ok, and some I deeply disliked, I guess there's a continuum from "exciting" to "frustrating".

jay_kyburz 11/4/2025||
I always like _my_ parts our code base. I never enjoy wading into my colleagues code. I'm sure they feel the same way.
riffraff 11/4/2025||
For sure, but I also get the same feeling about parts of the codebase I wrote but I had since forgotten.

The "what idiot wrote this? Oh, it was me" thing.

fennecbutt 11/4/2025||
Like tears in the rain.
boredtofears 11/3/2025|||
I have to spend 3 days working on someone else's "narratives that are more fun to apply their creativity to" all the time, even when my intuition and experience tells me it isn't a good idea. Sometimes my intuition is wrong. I've yet to meet a product manager that isn't doing this even when they claim to have all the data in the world to support their narrative.

Personally I don't think there's anything wrong with scratching that itch, especially if its going to make you/your team more comfortable long term. 3 days is probably not make-or-break.

TZubiri 11/3/2025|||
>if PostHog was able to do what they're doing on the stack you're abandoning, do you think that stack is actually going to limit your scalability in any way that matters?

Also, considering the project is an AI framework, do you think the language ChatGPT is built on is a worse choice than the language we use because it's in the browser?

pjmlp 11/4/2025||
You mean C++, right?

Because language bindings isn't really what makes ChatGPT tick.

TZubiri 11/4/2025||
https://github.com/openai/gpt-oss/tree/main

Sure a project can be based on more than 1 language. But it seems to be mostly python.

pjmlp 11/4/2025||
You missed these trees on the Python forest,

https://github.com/openai/gpt-oss/blob/main/pyproject.toml

https://github.com/openai/gpt-oss/blob/main/CMakeLists.txt

TZubiri 11/4/2025||
You are right, they are using Docker, therefore it's written in C.
philbo 11/3/2025|||
https://status.posthog.com/history
progbits 11/3/2025|||
I was just thinking... "BugHog? The platform famously broken more often than not?"

We have a whole posthog interface layer to mask over their constant outages and slowness. (Why don't we ditch them entirely? I, too, often ask this, but the marketing people love it)

zelphirkalt 11/5/2025|||
> Powered by Atlassian Statuspage

Is all I need to know.

frez1 11/5/2025||
It sounds like the author and their team were more comfortable with node.js than python. they acknowledge fastapi was a good alternative that could solve their issues and allow some code reuse, but decided not to because they just wanted to use node.

the gist of this blog post is this company knew and understood node better than python, so they migrated to what they knew.

Alir3z4 11/3/2025||
Async and Django don't mix well and I honestly see the whole Django Async as wasted resources, all those "a" prefixed functions etc.

To be honest, I never liked the way async is done in python at all.

However, I love Django and Python in general. When I need "async" in a http cycle flow, I use celery and run it in background.

If client side needs to be updated about the state of the background task, the best is to send the data to a websocket channel known to the client side. Either it's Chat response with LLM or importing a huge CSV file.

Simple rule for me is, "don't waste HTTP time, process quick and return quick".

robertlagrant 11/3/2025||
> If client side needs to be updated about the state of the background task, the best is to send the data to a websocket channel known to the client side.

SSE is nice.

revicon 11/4/2025|||
Right up until your user opens your site in more than 6 tabs.
robertlagrant 11/4/2025||
And then you need http2.
Oxodao 11/4/2025|||
(especially the Mercure protocol which makes stuff so simple)
bodhi_mind 11/3/2025|||
There’s also Django channels which is pretty sweet for certain tasks, especially websockets.

I use a combination or channels and celery for a few projects and it’s works great.

pdhborges 11/3/2025||
The problem with channels is that if you need to touch the ORM you will have to use a sync_to_async call which will block the event loop.
vb-8448 11/3/2025|||
+1

but I still hope at some point they will manage to fix the devx with django/python and async

ActorNightly 11/4/2025||
Django should just not be used period. Fast API + Uvicorn is all you need these days. It does the async for you.

With LLMS, you shit out working production ready web apps in 2 days now that are quite performant, as long as you don't care about code maintainability long term.

never_inline 11/4/2025||
FastAPI+Unicorn is good but it is barebones compared to what django already has. I can see why someone with experience in latter would not choose a new stack.

Also performance wise FastAPI + uvicorn have many pitfalls as well, most of them being of asyncio.

asa400 11/3/2025||
Folks, if you have problems doing async work, and most of your intense logic/algorithms is a network hop away (LLMs, etc.), do yourself a favor and write a spike in Elixir. Just give it a shot.

The whole environment is built for async from the ground up. Thousands and thousands of hours put into creating a runtime and language specifically to make async programming feasible. The runtime handles async IO for you with preemptive scheduling. Ability to look at any runtime state on a production instance. Lovely community. More libraries than you might expect. Excellent language in Elixir.

Give it a shot.

gchamonlive 11/3/2025||
I did an interview for the job I'm currently at, and we were discussing in it an architecture for live updating chats and I said I wouldn't reinvent the wheel and just use the approach Phoenix LiveView uses, which is to have a basic framework loaded client-side that would just apply diffs that comes from a websocket to the UI and have the chat update using those diffs. Turns out this is exactly the architecture they use in production.

People are reimplementing things that are first class citizens in elixir. Live content update, job runners, queues... Everything is built into the language. Sure you can do it all in typescript, but by then you'll be importing lots of libraries, reimplementing stuff with less reliability and offloading things like queues to third party solutions like pulsar or kafka.

People really should try elixir. I think the initial investment to train your workforce pays itself really quick when you don't have to debug your own schedulers and integrations with third party solutions. Plus it makes it really easy to scale after you have a working solution in elixir.

jacquesm 11/3/2025|||
I agree in principle but I think that your average Python developer that thinks that Node.js is an improvement over Python is going to have seizures if they need to switch to Elixer. It's a completely different way of working.
gchamonlive 11/4/2025||
I don't know... I'm your average python dev. I don't think nodejs is necessarily an improvement, but when I got to pick up a bit of elixir, and after struggling a bit with the many collection types and the pattern matching, when it clicked it was really eye-opening. So I don't think this is out of the league of the regular dev. I think if we were talking about Haskell that would probably apply, but elixir is fine. Even metaprogramming is very intuitive in elixir once you get the hang of it. It's just a very well designed language.
jacquesm 11/4/2025||
Indeed it is, and congratulations to making it to the other side of the ascent.

It's interesting, for some people Elixir really clicks, others can't make heads or tails of it. I don't mind Erlang either, but I understand that that is really an acquired taste.

gchamonlive 11/4/2025||
Still, there is a long way for me to actually be productive with elixir. Sure I can now solve some advent of code challenges with it, but I still haven't done a proper project with Liveview and OTP. I've seen enough though to have me convinced this is the way.
arvinsim 11/4/2025||||
I have always been interested in Elixir but have been putting off learning it because I don't see many job opportunities for it(at least here in Asia).

But your comment has convinced me to try it since I am having a bit of NextJS burnout.

dzonga 11/3/2025||||
you wouldn't need kafka or pulsar if you use elixir, why ?
gchamonlive 11/3/2025||
I said you'd need those if you were coding jobs in typescript natively, without aid of cloud primitives like AWS SQS and Lambda, not with elixir.
dzonga 11/3/2025||
sorry, maybe I wasn't clear enough when asking.

what about elixir that eliminates the need for kafka. simple queues I understand but kafka ?

gchamonlive 11/4/2025||
Sure Kafka is used for much more advanced applications. In autonomous microsservices if I'm not mistaken these topics could be even used as the source of truth so that each specialized database could be reconstructed by replay. I'm saying that for simple topics that are just used to coordinate job queues, elixir can handle it just fine.
hexbin010 11/3/2025|||
Persistent job queues?
doomspork 11/3/2025|||
Using a lot of Typescript and Python in my current role and I find myself missing that part of Elixir. Ecosystems are night and day though. For what we're doing we'd have to write far too many libraries ourselves in Elixir and don't have the time right now.
joshribakoff 11/3/2025|||
I don’t find the developer experience to be good, its not just the lack of types altogether but also the delays imposed by having compilation steps to run tests.

A lot of the affordances in the ecosystem have been supplanted by more modern solutions for many use cases, like Kubernetes.

Elixir also opens a number of footguns like abuse of macros; these are some of the reasons to second guess switching.

I think that one of the strongest reasons for switching would be that if you are willing to trade off all of this in exchange for the ability to do zero downtime deploys, not just graceful shutdowns and rollovers. Like if you’re building a realtime system with long lived interactions, like air traffic control system or live conferencing systems.

It can sometimes feel like an esoteric or regrettable choice for a rest api or rpc/event driven system. Even if you want a functional language there may be better choices like kotlin.

baobun 11/4/2025||
> its not just the lack of types altogether

??

Elixir is strongly but dynamically typed.

On the progress of static typing:

https://arxiv.org/abs/2306.06391

joshribakoff 11/16/2025||
Yea i was imprecise, thank you for clarifying.
raw_anon_1111 11/3/2025|||
This is an absolutely horrible idea. I’m not questioning the technology choice. But as someone interested in their career, it makes no sense to focus on a language or technology that is not popular. It’s both bad from the recruiting side trying to get developers who are smart enough to care about their n+1 job and the developer side.

There are probably less code samples and let’s be honest this is 2025, how well do LLMs generate code for obscure languages where the training data is more sparse?

asa400 11/3/2025|||
Maybe for you! That's your call. I'm also interested in my career.

I've had 3 Elixir jobs and 2 Rust jobs in the last 10 years. All were on real products, not vaporware. I learned a ton, worked with great people, and made real friends doing it.

Luck? Skill? Who knows. It's not impossible to work with the technology of your choice on problems you find interesting if you're a little intentional.

Nothing ever gets better if everybody just does what's already popular.

bargainbin 11/4/2025||||
I’ve made a very lucrative career moving from .NET to BEAM. I don’t even work with it currently but the fact I’ve shipped it for some pretty niche systems shows versatility and consistently goes in my favour when getting hired.
buggy6257 11/4/2025||||
I work at a company doing full-stack Elixir with most of our devs all heavily using AI as they please to augment their workflow, and our CTO was genuinely concerned that our main competitor, a Python shop, had a leg-up on us for this exact reason.

He spent time running benchmarks for 0-1 apps and all kinds of other metrics and found basically no appreciable difference in the speed or accuracy of AI at generating Elixir vs. Python. Maybe some difference, but honestly it just doesn't exist enough to matter.

riffraff 11/4/2025||||
About LLMs: I did last year's advent or code with Elixir and when I forgot to turn off copilot it had no trouble writing whole implementations of functions, even if I had a very idiosyncratic style.

Most code is boilerplate and that's where LLMs shine, I don't think this specific issue is very important.

b1az 11/4/2025||||
> this is 2025, how well do LLMs generate code for obscure languages where the training data is more sparse?

You'd be surprised: https://github.com/Tencent-Hunyuan/AutoCodeBenchmark/blob/b1...

Bolwin 11/5/2025||
Wow.. Elxir is the highest? That's interesting
AllegedAlec 11/4/2025||||
> But as someone interested in their career, it makes no sense to focus on a language or technology that is not popular

A: why in gods name B: Every language, every framework and every tech stack is 1 month to 5 years away from being legacy crap. Unless you're learning something like KOBOL it's better to be able to use a variety of languages and show that you can adapt.

raw_anon_1111 11/4/2025||
Java has been around and popular in the enterprise since 2002 and .Net not too far behind. JavaScript will survive the heat death of the universe.
morshu9001 11/3/2025||||
Reminds me of the time I was on a team doing stuff in Erlang for no reason
moralestapia 11/3/2025|||
>how well do LLMs generate code for obscure languages where the training data is more sparse

LOL. Speaking about absolutely horrible ideas ...

raw_anon_1111 11/3/2025||
You might not like LLM code generation or corporations encouraging it. Just like I might not like gravity. But I am not going to jump out of a 25 story building. I accept reality for what it is.
moralestapia 11/3/2025||
Many people code out of curiosity and/or to learn new things and dgaf about whether recruiters will have trouble finding them, mega-lmao.

As an acceptor of reality, you can begin to accept that as well.

raw_anon_1111 11/3/2025||
I have a strange feeling that most people haven’t found a method to get over there addictions to food and shelter. If they want to exchange labor for money to support those addictions, they have to care about what recruiters want whether external recruiters or internal recruiters.
dlx 11/4/2025|||
As someone who who's a polygot programmer, I've always agreed with this in theory; however, the biggest challenge I've found in giving Elixir a shot is that, well the job market doesn't seem to favor ANY elixir jobs out there...especially for someone who's only made 'toy' apps in Phoenix. And for prototyping apps, I'm just faster in Ruby/Rails to make it worth it PLUS if you want to debug ML/LLM scripts you have to know Python anyways.

Any recommendations for someone looking to break into the Elixir space in a serious (job-related/production app) way?

asa400 11/5/2025||
There are quite a few Elixir shops that are willing to hire people who don't have a ton of experience with Elixir but have experience building and understanding systems generally.

So my advice is, try to bolster your story that you can design and build systems (regardless of language), learn what is needed to get the job done, and _communicate_ your knowledge of those systems to people. Good teams will recognize this regardless of prior specific tech.

Source: I've been on hiring panels at multiple companies that used Elixir extensively and the factors that led to us making offers to candidates were rarely their preexisting Elixir experience.

metadata 11/3/2025|||
A lovely language with an incredible web framework (Phoenix, LiveView). However, not easy to pick up for people with only imperative programming experience.

I had to switch my project to .NET in the end because it was too hard to find/form a strong Elixir team. Still love Elixir. Indestructible, simple, and everything is easy once you wrap your head around the functional programming.

It. Just. Works.

mikepurvis 11/3/2025||
As someone who has spent my whole career in somewhat niche things (ROS, OpenWRT, microcontrollers, Nix), I think the answer for how to hire for these is not to look for someone who already has that specific experience but rather look for someone curious, the kind of person who reads wikipedia for fun, an engineer who has good overall taste and is excited to connect the dots between other things they've learned about and experimented with.

Obviously that's not going to give you the benefit of a person who has specifically worked in the ecosystem and knows where the missing stairs are, which does definitely have its own kind of value. But overall, I think a big benefit of working in something like Elixir, Clojure, Rust, etc is that it attracts the kind of senior level people who will jump at the opportunity to work with something different.

raw_anon_1111 11/3/2025|||
And what happens when I’m looking for that next job? I haven’t interviewed for a pure developer job since 2018. But the last time I did, I could throw my resume up on the air and find a job as someone experienced with C# and knew all of the footguns and best practices and the ecosystem. I’m sure the same is true for Java, Typescript, Python, etc.
jacquesm 11/3/2025|||
This is excellent advice.
mikepurvis 11/3/2025||
Thanks.

One nice side effect of having done this is having a small rolodex of other people who are like that.

So, like, if I had a good use case for Elixir and wanted a pal to hack on that thing with, I know a handful of people who I'd call, none of whom have ever used Elixir before but I know would be excited to learn.

jacquesm 11/3/2025||
Yes, same here. And that has come in very handy more than once. But my merry band of friends isn't getting any younger, I think the youngest in our group is now mid 30s or so, the bulk between 50 and 60.
never_inline 11/4/2025|||
Can someone explain a plebian C/python/java/go programmer with good idea about languages & runtimes:

==> what makes erlang runtimes so special which you don't get by common solutions for retries etc?

eaglelamp 11/4/2025||
Normal Erlang code has a fixed number of reductions (function calls) before it must yield to a scheduler. Processes also have their own stacks and heaps and run garbage collection independently. The result is that no single process can stop the whole system by monopolizing CPU or managing shared memory.

The Erlang runtime can start a scheduler for every core on a machine and, since processes are independent, concurrency can be achieved by spawning additional processes. Processes communicate by passing messages which are copied from the sender into the mailbox of the receiver.

As an application programmer all of your code will run within a process and passively benefit from these properties. The tradeoff is that concurrency is on by default and single threaded performance can suffer. There are escape hatches to run native code, but it is more painful than writing concurrent code in a single-threaded by default language. The fundamental assumption of Erlang is that it is much more likely that you will need concurrency and fault tolerance than maximum single thread performance.

morshu9001 11/3/2025|||
Yes but NodeJS is also built for async. I get why Discord or FB Messenger use Elixir or Erlang, but they're huge scale.
ch4s3 11/4/2025||
Elixir is dead simple to use and the LLMs do a good job with the Phoenix boilerplate now. Hex.pm and Mix for building and dependency management are miles better than anything node has to offer as well. The developer experience is just really good.
te_chris 11/3/2025||
Yeah moving from python to node for concurrency is insane.
coldtea 11/3/2025|||
Moving from Python to Node for per-process fully-fleshed out async and share-nothing concurrency however is perfectly sane.
pjmlp 11/4/2025||||
Using any of them for backend is insane, but what do I know, I have to suck it up and use Next.js for some SaaS extension SDKs, while I would rather be using JVM, CLR, or even Go with its spartan design.
nawgz 11/3/2025||||
JS haters could stand to understand the language has strengths even if it has well known warts.
morshu9001 11/3/2025|||
That's the main reason to move. Same reason people moved from Java to Kotlin, except that might change now with vthreads.
davedx 11/3/2025||
Same experience working on FastAPI projects. I don’t know how big production apps are maintained (and supported operationally) with the mess that is python+async+types.

Conversely all the node+typescript projects, big and small, have been pretty great the last 10+ years or so. (And the C# .NET ones).

I use python for real data projects, for APIs there are about half a dozen other tech stacks I’d reach for first. I’ll die on this hill these days.

cjonas 11/3/2025||
100% same experience. If it were up to me, I'd started with typescript, but the client insisted on using a python stack (landed on FastMCP, FastAPI, PydanticAI).

While, `PydanticAI` does the best it can with a limited type system, it just can't match the productivity of typescript.

And I still can't believe what a mess async python is. The worst thing we've encountered was a bug from mixing anyio with asyncio which resulted in our ECS container getting it's CPU pinned to 100% [1]. And constantly running into issue with libraries not handling task cancellation properly.

I get that python has captured the ML ecosystem, but these agent systems are just API calls and parsing json...

[1](https://github.com/agronholm/anyio/issues/884)

zzzeek 11/3/2025|||
async python has problems, but "anyio exists" is not one of them that can be blamed on python, simply dont use weird third party libraries trying to second guess the asyncio architecture

edit: ironically I'm the author of a weird third party library trying to second guess the asyncio architecture but mine is good https://awaitlet.sqlalchemy.org/en/latest/ (but I'll likely be retiring it in the coming year due to lack of interest)

cjonas 11/4/2025||
I don't recall the exact situation but am I suppose to just know which async library each dependency is using? It reminds of of the early days of promises in JavaScript.
triyambakam 11/3/2025|||
I don't really see how you're comparing Pydantic AI here to Typescript. I'm assuming you meant simply Pydantic.
cjonas 11/3/2025||
Just comparing an agent framework written in python (with focus on being "typesafe") to one (any) written in typescript
triyambakam 11/3/2025||
That's a very poor comparison then and not very useful?
TZubiri 11/3/2025|||
>Same experience working on FastAPI projects. I don’t know how big production apps are maintained (and supported operationally) with the mess that is python+async+types.

In my experience async is something that node.js engineers try to develop/use when they come from node.js, and it's not something that python developers use at all. (with the exception of python engineers that add ASGI support to make the language enticing to node developers.)

davedx 11/4/2025||
But then how to you build a performant API in python if you don't use async? Do you give your API's giant thread pools?
jdsleppy 11/4/2025|||
Multiple processes, multiple threads per process, and/or greenlets (monkey patch network calls, like async but no keywords involved). Scale out horizontally when there's a problem. It could get expensive.
kurtis_reed 11/4/2025||||
Async isn't about performance, the overhead it eliminates is small
TZubiri 11/4/2025|||
You spawn a thread when you get a request
simlevesque 11/3/2025|||
Yeah I did my first project with FastAPI earlier this year with experience in other languages and I couldn't believe how bad it was.
com2kid 11/3/2025|||
The funny thing is all the python people will tell you how great FastAPI is and how much of an improvement it is over what came before.

FastAPI does have a few benefits over express, auto enforcing json schemas on endpoints is huge, vs the stupidity that is having to define TS types and a second schema that then gets turned into JSON schema that is then attached to an endpoint. That IMHO is the weakest link in the TS backend ecosystem, compiler plugins to convert TS types to runtime types are really needed.

The auto generated docs in FastAPI are also cool, along with the pages that let you test your endpoints. It is funny, Node shops setup a postman subscription for the team and share a bunch of queries, Python gets all that for free.

But man, TS is such a nice language, and Node literally exists to do one thing and one thing only really well: async programming.

simlevesque 11/3/2025|||
> That IMHO is the weakest link in the TS backend ecosystem, compiler plugins to convert TS types to runtime types are really needed.

Just define all your types as TypeBox schemas and infer the schema from that validator. This way you write it once, it's synced and there's no need for a compiler plugin.

https://github.com/sinclairzx81/typebox?tab=readme-ov-file#u...

com2kid 11/3/2025||
That is nice and all, but it is one of many libraries that solves a problem that shouldn't exist.

The TS compiler should either have an option to pop out JSON schema from TS types or have a well defined plugin system to allow that to happen.

TS being compile time only really limits the language. It was necessary early on to drive adoption, but now days it just sucks.

WorldMaker 11/4/2025||||
Zod [0] isn't too bad for runtime types and runtime type evaluation. It even has JSON schema output now [1], though most of my API uses of Zod have been with Hono's "RPC" [2] which does a bunch of type magic to build a type-safe API client from your API types directly (in projects where you can share front-end and back-end types).

[0]: https://zod.dev/

[1]: https://zod.dev/json-schema

[2]: https://hono.dev/docs/guides/rpc

nawgz 11/3/2025|||
Maybe you have non TS clients, but I moved to tRPC backends and now my consumers are perfectly typed at dev time, combined with pnpm monorepos I’m having a lovely time.
kurtis_reed 11/4/2025|||
What's bad about it?
kurtis_reed 11/4/2025|||
What's messy about python+async+types?
65 11/4/2025|||
Hell I write ETL pipelines in Typescript since it's just... way easier to deal with. Not doing any crazy ML processing. But the Node ecosystem is giant and I'm a huge fan of the ergonomics of Typescript. And since Typescript is so popular it's very easy for other developers to make changes in my code.
all2 11/3/2025||
> Same experience working on FastAPI projects. I don’t know how big production apps are maintained (and supported operationally) with the mess that is python+async+types.

Very painfully.

I avoid the async libs where possible. I'm not interested in coloring my entire code-base just for convenience.

megaman821 11/3/2025||
As a long-time Django user, I would not use Django for this. Django async is probably never the right choice for a green-field project. I would still pick FastAPI/SQLAlchemy over Express and PostHog. There is no way 15 different Node ORMs are going to survive in the long run, plus Drizzle and Prisma seem to be the leaders for now.
ccanassa 11/5/2025||
FastAPI/SQLAlchemy won’t be more scalable than a typical Django setup. The real bottleneck is the threading model, not the few microseconds the framework spends before handing off to user code. Django running under uWSGI with green threads can outperform Go-based services in some scenarios, largely thanks to how efficient Python’s C ABI is compared to Go.
raverbashing 11/3/2025|||
Agree

Django is great but sometimes it seems it just tries to overdo things and make them harder

Trying to async Django is like trying to do skateboard tricks with a shopping cart. Just don't

liquidpele 11/3/2025||
Async in Python in general really… The way they implemented it is basically a valley of footguns and broken dreams.
morshu9001 11/3/2025||
I'd skip the ORM, Postgres is already designed for direct use on backends.
eYrKEC2 11/5/2025|||
Much as Lisp'ers say,

    Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
If one says, "we don't use an ORM", you will incrementally create helper functions for pulling the data into your language to tweak the data or to build optional filters and thus will have an ad hoc, informally-specified, bug-ridden, slow implementation of half of an ORM.

There is a time and place for direct SQL code and there is a time and place for an ORM. Normally I use an ORM that has a great escape hatch for raw SQL as needed.

morshu9001 11/5/2025||
I've always used SQL directly since I stopped using ORMs, and it didn't result in a halfway implemented ORM. Maybe back when there was no jsonb for your blob o' fields cases, it was different.

But yeah don't do a high level lang's job in C or C++

ccanassa 11/5/2025||||
The main advantage of an ORM isn’t query building but its deep integration with the rest of the ecosystem.

In Django, you can change a single field in a model, and that update automatically cascades through to database migrations, validations, admin panels, and even user-facing forms in the HTML.

morshu9001 11/9/2025||
I'd have to try this for myself before judging it. Apple's CoreData tried and miserably failed to do this, and I wasn't fond of the Laravel ORM either, but Django is probably a better example than those.
remify 11/4/2025||||
ORMs are mostly useless they make easy queries easier et hard query a lot harder.
mrits 11/4/2025|||
I'd skip the ORM as well but your reasoning doesn't make any sense
languagehacker 11/3/2025||
I don't see it mentioned enough in the comments here, but not considering Celery as an alternative to Django + async really is the missing puzzle piece here. Aside from application-level options that weren't explored, I'm wondering whether handling some of the file IO stuff with, for instance, nginx, might be a better fit for their use case.

Once you're in the situation of supporting a production system with some of the limitations mentioned, you also owe it to yourself to truly evaluate all available options. A rewrite is rarely the right solution. From an engineering standpoint, assuming you knew the requirements pretty early on, painting yourself into a bad enough corner to scrap the whole thing and pick a new language gives me significant pause for thought.

In all honesty I consider a lot of this blog post to be a real cause for concern -- the tone, the conflating arguments (if your tests were bad before, just revisit them), the premature concern around scaling. It really feels like they may have jumped to an expensive conclusion without adequate research.

In an interview, I would not advance a candidate like this. If I had a report who exhibited this kind of reasoning, I'd be drilling them on fundamentals and double-checking their work through the entire engineering process.

Kwpolska 11/3/2025||
I tried to use Celery for something extremely trivial (granted, 5+ years ago). It was so badly documented and failed to do basic things I would expect from a task queue (like progress reporting) I have no idea why it was and still is popular.
languagehacker 11/3/2025|||
Just because you couldn't figure it out doesn't mean the capability wasn't there. More than ten years ago at this point I was running a massively scaled Celery + RabbitMQ + Redis deployment with excellent off-the-shelf reporting using Flower.
integralid 11/4/2025||
I'm going to back GP, eight years ago my team developed a system that was basically an async, scheduled, async task queue, we used celery, and it was so buggy and so troublesome that at some point we switched to a hastily hacked own solution and it worked better.

It's entirely likely that we did something wrong and misused celery. But if many people have problems with using a system correctly then it's also something worth considering.

andrewstuart 11/4/2025|||
I hated celery so much I wrote my own message queue.

There’s not much software I really dislike but Celery is one.

A nightmare within a nightmare to configure and run.

ksclk 11/3/2025|||
Hi! Could you please tell me what use cases would nginx be better for, outside of serving static files?

Moreover, having worked with Django a bit (I certainly don't have as much experience as you do), it seems to me that anything that benefits from asynchrony and is trivial in Node is indeed a pain in Django. Good observability is much harder to achieve (tools generally support Node and its asynchrony out of the box, async python not so much), Celery is decent for long running, background, or fire and forget tasks, but e.g. using it to do some quick parallel work, that'd be a simple Promise.all() is much less performant (serialize your args, put it in redis, wait for a worker to pick it up, etc), doing anything that blocks a thread for a little bit, whether in Django or Celery,is a problem, because you've got a very finite amount of threads (unless you use gevent, which patches stdlib, which is a huge smell in itself), and it's easy to run out of them... Sure, you can work around anything, but with Node you don't have to think about any of this, it just works.

When you're still small, isn't taking a week to move to Node a better choice than first evaluating a solution to each problem, implementing solutions, each of which can be more or less smelly (which is something each of your engs will have to learn and maintain... We use celery for this, nginx for that, also gevent here because yada yada, etc etc), which in total might take more days and put a much bigger strain on you in the long term? Whereas with Node, you spend a week, and it all just works in a standard way that everyone understands. It seems to me that exploring other options first would indeed be a better choice, but for a bigger project, not when the rewrite is that small.

Thank you for your answers!

dzonga 11/3/2025||
[dead]
JackSlateur 11/3/2025||
"Python async sucks", then rants about django

"Python doesn't have native async file I/O." - like almost everybody, as "sane" file async IO on Linux is somehow new (io_uring)

Anyway ..

jitl 11/3/2025||
libuv has provided an async interface for io using a worker thread pool for a decade, no dependency on io_uring required. I guess the threadpool they mention that aiofiles uses is written in python, so it gives concurrency but retains the GIL, so no parallelism. Node's libuv async stuff moves all the work off the main thread into c/c++ land until results are ready, only when dealing with the completed data read event does it re-enter the NodeJS "GIL" JavaScript thread.
hinkley 11/3/2025||
Libuv has had io_uring integration for almost 18 months if you’re not on an old kernel or old hardware.

They claim about an 8x improvement in speed.

danudey 11/3/2025|||
To be clear: libuv has had the ability to offload (some?) I/O operators to io_uring since v1.45.0, from 2023, and that's the 8x speed improvement. 2024 is when node.js seemed to enable (or rather, stop disabling) io_uring by default in its own usage of libuv.
hinkley 11/3/2025||
Yeah if you look at the libuv release history there’s been a lot of adding and subtracting since then. It’s clearly not all settled but there are chunks.
jitl 11/3/2025|||
that's great! just saying io_uring has never been a required dependency to write application logic that avoids blockage on reads.
morshu9001 11/3/2025|||
Python async does suck though
kurtis_reed 11/4/2025||
Why?
morshu9001 11/5/2025||
Historically the main way was Py threads that have all the downsides of OS threads (overhead + data races) without the parallelism advantage (due to GIL), with a confusing API on top. There was no cooperative multitasking until asyncio, at which point it was too late. There are competing solutions now, and many users are thoroughly confused.

And I'm guessing the reason they didn't do greenthreading is it'd severely complicate working with C/native libs.

antirez 11/5/2025||
Sane async does not need io_uring. All the non-linear-time select(2) alternatives are good enough.
JackSlateur 11/5/2025||
How do you do that ? More details would be welcome
stackskipton 11/3/2025||
Django is massive and ton of baggage to be carrying if you are only doing REST APIs.

This sounds like standard case going with what developers know instead of evaluating tool for job.

isodev 11/3/2025||
I think the baggage goes both ways - Django has the advantage of being a "complete & proven recipe" vs. Node where you try to lego-together an app out of dependencies that have deprecation warnings even in their latest versions.
everforward 11/3/2025|||
> Django has the advantage of being a "complete & proven recipe"

I work on a large Django codebase at work, and this is true right up until you stray from the "Django happy path". As soon as you hit something Django doesn't support, you're back to lego-ing a solution together except you now have to do it in a framework with a lot of magic and assumptions to work around.

It's the normal problem with large and all-encompassing frameworks. They abstract around a large surface area, usually in a complex way, to allow things like a uniform API to caches even though the caches themselves support different features. That's great until it doesn't do something you need, and then you end up unwinding that complicated abstraction and it's worse than if you'd just used the native client for the cache.

macNchz 11/4/2025|||
I’ve always found the Django codebase to be easy to read and override, making it pretty straightforward to color outside the lines.
pdhborges 11/3/2025||||
I don't agree with this cache take. Adding operations to the cache is easy. Taking the django-redis project as an example there are only two levels until you reach redis-py: The cache abstraction and the client abstraction.
DangitBobby 11/3/2025|||
I'm having a hard time imagining a case where you'd be worse off with Django (compared to whatever alternative you may have chosen) in the case where the happy path for the thing you're trying to do doesn't exist natively in Django. Either way you're still farming out that capability to custom code or a 3rd party library.

I guess if you write a lot of custom code into specific hooks that Django offers or use inheritance heavily it can start to hurt. But at the end of the day, it's just python code and you don't have to use abstractions that hurt you.

chrisweekly 11/3/2025|||
"dependencies that have deprecation warnings even in their latest versions"

Could you be more specific? Don't get me wrong, I'm well aware that npm dependency graph mgmt is a PITA, but curious where you an into a wall w/ Node.

dec0dedab0de 11/3/2025|||
you can just run part of django. So the negatives of it being “massive” is really just the size of the library that will just be sitting there on disk. which is really not a big deal in most situations.

As far as going with what you know vs choosing the best tool for the job, that can be a bit of a balancing act. I generally believe that you should go with what the team knows if it is good enough, but you need to be willing to change your mind when it is no longer good enough.

e145bc455f1 11/3/2025|||
How would you compare this with spring?
stackskipton 11/3/2025||
Spring is massive as well but since Java is compiled, it’s baggage is less noticeable.
mrits 11/4/2025||
Curious what you think a .pyc is
stackskipton 11/6/2025||
Python compiles and then interpret currently. Before you throw things back, learn how a language works.
mrits 11/11/2025||
Maybe you should start by learning what Java byte code is
icedchai 11/3/2025||
I worked at a mid-size startup that was still running on Python 2.7 and Django for their REST APIs, as late as 2022. It was pretty meh and felt like traveling back in time 10 years.
JimDabell 11/3/2025|||
Python 2.7 was released in 2010. Of course using it in 2022 felt like travelling back in time ten years‽
mywittyname 11/3/2025||
2.7 was end-of-life in 2020! And Python 3 outdates 2.7 by a few years.

A company using 2.7 in 2022 is an indicator that the company as a whole doesn't really prioritize IT, or at least the project the OP worked on. By 2017 or so, it should have been clear that whatever dependencies they were waiting on originally were not going to receive updates to support python3 and alternative arrangements should be made.

icedchai 11/3/2025||
You captured the fundamental issues. There were mountains of technical debt. I recall encountering a dependency that had not been updated in over 10 years.
Izkata 11/3/2025||
We have VB deployments that haven't been changed at all in about that long. Finally got approval to do a rewrite last year, which is python 3.6 due to other dependencies we can't upgrade yet.

It got this bad because the whole thing "just worked" in the background without issues. "Don't fix what isn't broken" was the business viewpoint.

gjvc 11/3/2025|||
python2 will have that effect tbh
tracker1 11/3/2025||
I probably would have pushed for Hono as the underlying framework... That said, I've been a fan of Koa/Oak over Express for a very long time. For API usage, the swagger+zod integration is pretty decent, though it changes the typical patterns a bit.

All-in, there's no single silver bullet to solving a given issue. Python has a lot of ecosystem around it in terms of integrations that you may or may not need that might be harder with JS. It really just depends.

Glad your migration/switch went relatively smoothly all the same.

davedx 11/3/2025|
It depends on your use case. Exactly. If you’re building big data intensive pipelines with lots of array manipulation or matrix multiplications you know what will shine. Building user facing APIs, use something with types and solid async.
tracker1 11/3/2025||
Matching your latter definition, I'd be inclined to go with Rust or C#... that said, you can go a long way with TS in Node/Deno/Bun/Cloudflare/Vercel, etc.
move-on-by 11/3/2025|
> At this point, some people are probably screaming at their screens going: "just use FastAPI!" -- and we did indeed consider it.

Working with both sync Django and async FastAPI daily, it’s so easy to screw up async FastAPI and bring things to a halt. If async is such the huge key feature they seem to think it is for their product, then I would agree moving away from Python early while it’s still relatively easy is the right call.

> and we had actually already written our background worker service in Node,

Ok well that’s a little bizarre… why use Django to begin with if you are not going to use the huge ecosystem that comes with it. New Django has first-class support for background workers, not that Celery is difficult to get setup. It’s sounds like the engineering team just started building things in what they knew without any real technical planning and the async hiccup is more or less an excuse to get things in order after the fact.

kurtis_reed 11/4/2025|
> it’s so easy to screw up async FastAPI and bring things to a halt

For example?

move-on-by 11/5/2025||
I think this stackoverflow answer does a good job explaining the nuances: https://stackoverflow.com/a/71517830
More comments...