9 ms·
Developing a Modern Full-Stack Application: Choosing the Right Tech Stack
- kyruzic 2y agoTypescript (nodejs) backends are not performant, and your ultra modern stack is going to just cause you issues going forward if you need to scale. Prisma is really bad too, slow queries and no flexibility. If you ever need to do any sort of complex query you will just have to write sql anyway. And typescript is only sort of static typing. These technologies are great for prototyping and building a v1 release to see if what you're trying to achieve is actually possible, but you will regret it later on. The reason I know this, I work at a startup where we literally had the same backend stack and its been nothing but preformance issue after preformance issue. And it all needs to be replaced. We would have been better off building everything with go/rust in the first place. Or even java.
- willsmith72 2y agoi don't agree at all. nodejs backends are as performant as you build them. the whole premise of node was async io, so if you're doing a bunch of blocking stuff then yeah, you're going to have issues. otherwise there's nothing innately non-performant about the platform. it's impossible to debate more without going into details on your performance issues. typical backend architecture for any platform these days is the scalable container model, if you wanted scale-to-zero i wouldn't necessarily use node because of cold starts. prisma can be great, can be slower than writing your own query, but that's the whole point of it. most of the time, it works and you can forget about queries and typings. when it doesn't, you can just eject to raw sql anytime you want. i'm not a total nodejs fanboy, and have used more jvm (java/kotlin/scala) in my life, but if i was building a web-app today i'd absolutely consider node for all the reasons the author listed
- kyruzic 2y agoNodejs backends are not "as performant as you build them" nodejs is slow! This is an undeniable fact. If you ever have to do anything computationally intensive, which every backend at some point will nodejs will become the bottleneck.
- throwaway60330 2y agoIt's as fast or even faster than Java that you mentioned. In my experience, comparable to Golang.
- alex_lav 2y agoGenerally anyone that references performance/bottlenecks without data, they’re just parroting their bias. This post is “nu uh!”, but with more words.
- SantiagoElf 2y agoNodejs is slooooooooooooooooooooooooooooow. [0] [0] - https://www.techempower.com/benchmarks/#hw=ph&test=composite§ion=data-r22 https://www.techempower.com/benchmarks/#hw=ph&test=composite...
- throwitaway1123 2y agoWhat do you think about how well uWebSockets.js performed in the TechEmpower benchmark? Just js is admittedly experimental, but it has the fourth highest score, and the highest score of any non-Rust framework as well which I found interesting. Elysia (a Bun framework) did pretty well too. Deno would have probably scored well too (it uses Rust's Hyper crate under the hood), but they're only running a single instance of the server despite Deno supporting the Linux SO_REUSEPORT socket option, which is important because the test is run on three servers with Intel Xeon Gold 5120 Processors that have 14 cores and 28 hyperthreads [0]. [0] https://github.com/TechEmpower/FrameworkBenchmarks/tree/9f0c8e1f7f140885ad80feb437e2c90a5c64664f/frameworks/TypeScript/deno https://github.com/TechEmpower/FrameworkBenchmarks/tree/9f0c...
- stefanos82 2y agoJust go to its repo https://github.com/uNetworking/uWebSockets.js https://github.com/uNetworking/uWebSockets.js and see the uWebSockets submodule dependency that it's written in C++ (90.9%) and C (6.8%)...so sure, a "fair" comparison indeed with vanilla implementation!
- esafak 2y agoI would not use prisma for anything until they fix https://github.com/prisma/prisma/discussions/12715 https://github.com/prisma/prisma/discussions/12715
- bernawil 2y agoI wouldn't use find commands beyond the simplest Join. The beauty of Prisma is raw queries, because they're compiled and type-checked against your Entities. That's the whole appeal, IMHO.
- throwaway60330 2y agoNode.js backend performance is comparable to Java. Perhaps you had bad developers - trust me, if they screwed it up so bad they wouldn't be able to make your Java backend any faster, and probably couldn't get Go or Rust to work at all.
- kyruzic 2y agoGo is perhaps the simplest language to learn there is. It's almost impossible to not get it to work because it has so few things you can actually do. And nodejs only preforms well in hello world benchmarks, real world applications are nothing like that. Once you start having to manipulate large arrays or do any large amount of math nodejs preformance goes into the dumpster.
- speedgoose 2y agoI have never seen a glorified CRUD backend suffering from array or math operations. What kind of backend are we talking about?
- rlt 2y ago> Once you start having to manipulate large arrays or do any large amount of math nodejs preformance goes into the dumpster. We’re talking about web applications, no? You probably shouldn’t be manipulating large arrays or doing large amounts of math directly in your web application server. That should be isolated in some type of service or worker, which could be written in another language. Or maybe there’s a NumPy-like package for Node.js, I haven’t looked. The question then is where do you draw that line of using another language? It probably depends on your application, but I think Node.js is perfectly suitable for typical web applications backends.
- Fire-Dragon-DoL 2y agoAny large query result in a large array, so I would disagree on that point. Web apps deal with fairly big data structures, if nothing due to orms.
- kossTKR 2y agoThis sounds weird to me. What kind of scale / traffic did you have? Must be incredible read write heavy with millions of users? I'm saying this because i myself have, and lots i know, have launched production sites with 100s of thousands of users on ready-made stacks like, Laravel, Rails, Flask (Php, Ruby, Python). But it's my impression that these fall short on millions of users and enormous concurrent traffic, but then you're already at huge evaluation, years into your project, or have 200+ positions, ie. you've already refactored your project multiple times.
- kyruzic 2y agoThat's why you shouldn't use slow backend technologies in the first place because you get to the point where you need preformance and it's impossible because your limited by extremely slow runtime you chose initially because it was flashy (not even easier to developer for) when you could have just chosen something better from the start. Simple crud apps can get by fine with those technologies, but in the future I'd still never use it because you're leaving huge amounts of performance gains on the table for virtually no benefit. I don't buy the argument that javascript is just easier to develop for because it's simply not. The js ecosystem is a disaster.
- kossTKR 2y agoWhat kind of application are you talking about? I agree to a degree but we haven't run into performance issues with say 100k users, what traffic did you handle, what was the business case? Again sounds like you are running some complex math heavy operation like say a weather service, national taxi service with lots of pathfinding, a global gaming platform etc? Curious to know what exactly you are talking about here? Because normally you just outsource the "heavy stuff" to some remote API, service, etc. you can write in a hyper efficient language anyway.
- bcaxis 2y agoMaking stuff faster is relatively straightforward engineering. Optimisation is a favored past time of many engineers. Getting stuff that people value enough to pay for, to make money, is the hard part. Any friction you put into the value creation process because "optimizing for future problems" is just doing it wrong.
- zeroCalories 2y agoMany companies are not throttled by server language performance. Performance in many cases will depend on your database, geolocation, and caching techniques over nodejs vs go. Nothing wrong with prioritizing developer experience.
- kyruzic 2y agoI do agree with this, but I'd argue the developer experience of nodejs with Typescript is far worse than that of rust/go
- dboreham 2y agoAgree. JS/TS is not a good environment for large software projects maintained over a long period of time. I'm not 100% convinced Rust is either, yet. cargo seems to be a dumpster fire. Build tools generate TB of mystery disk bloat. Obsession with async... hopefully these issues can be resolved.
- brink 2y ago> Build tools generate TB of mystery disk bloat. No, it's not TB, it's a few GB for small projects, and tens of GB for large projects. Rarely does a project ever get over 30-40GB. > Obsession with async... If you're going to want any amount of decent performance, you're going to have to deal with async. That's just the nature of IO bound applications.
- HumanOstrich 2y ago> JS/TS is not a good environment for large software projects maintained over a long period of time. VSCode disagrees with you. Its codebase is fascinating btw.
- rohan_ 2y agoReact Server Components is the best possible DX for a react backend
- dboreham 2y agoSounds like the issue wasn't the performance of TS per se, but rather the use of some ORM led to inefficient database queries being executed. This sort of screwup is possible in all languages.
- brink 2y agoI just built an app with Rust and Svelte with ~25k LoC, the app was solid, and working on it was a joy. New team lead got hired, wasn't familiar with Rust, said we'd have trouble hiring Rust devs, and threw it all out. We're now building a Python / ReactJS app from scratch.
- mrcartmeneses 2y agoSpeak to your academic friends for advice on how to get him fired. Do this ASAP for the sake of the company and do not drop the ball once he’s gone. You may have to step into his role
- sotix 2y agoFor what it’s worth, I’d be much more interested in working for your company using Rust and Svelte compared to python and react. If you need someone with experience working with Rust and Svelte, I’m looking for work and value making quality decisions like you did. Now you can point to at least one dev who has the skills your team lead was concerned about finding.
- HumanOstrich 2y ago> New team lead got hired, wasn't familiar with Rust, said we'd have trouble hiring Rust devs, and threw it all out. Depending on the company you work for, this was probably a good call on their part.
- aranchelk 2y ago> typescript is only sort of static typing Can you elaborate on this?
- brink 2y agoIt's progressively typed because it has to coexist with untyped Javascript code and libraries.
- rlt 2y agoSure, but you can enable TypeScript options and institute lint rules prohibiting use of untyped code.
- willsmith72 2y agoi love typescript, but that's still not the same as static typing. imagine a full stack typescript app with a blog type type Blog = { name: string } everything works fine until you decide to refactor "name" to title. you update the backend and typescript code and deploy the change type Blog = { title: string } user john never closes his browser and leaves your website open. he clicks on a new blog post. his client typescript expects a name, the server gives a title, and crash, "Cannot read properties of undefined". i still choose nodejs backends, but you obviously have to keep in mind it's not statically typed. same with "any", my coworker could take my blog and modify it. it's preventable, but with large teams and codebases still prone to error. (blog as any).title = { summary: 'blah', full: 'blah blah blah' }
- rlt 2y agoTypeScript is definitely statically typed. It is not a 100% “sound” type system, but very few languages actually are (Haskell, Reason, etc) And in your example of loading data from a server, if you have appropriate lint rules set up your editor and linter will warn you when you pass “any” typed data (such as that returned by fetch’s response.json()) to something expecting another type. You can use something like zod or yup to validate the data is the type you expect before passing it the rest of your typed code, thereby containing possible type errors to a known location where you can gracefully handle it. This is a problem with any language that accepts typed data from an external system, certainly not unique to TypeScript.
- aerhardt 2y agoI’m not partial to Node.js backends for many reasons, primary being that I prefer batteries-included web frameworks and the choices are very limited in the JS backend world… But I have such a hard time believing that Node.js is inherently non-performant when there are so many counter-examples of large scale applications that do just fine on it. I understand that the single-threaded nature of JS can be a bottleneck for certain workloads, but without further explanation I’m going to concur with others and say that reading your comment, it’s hard to discard you guys made a mess on your own... Which at least in my experience often comes down to how difficult it is to build in Node.js precisely because of how “minimalistic” and “unopinionated” everything tends to be… You’d better know what you’re doing when there’s no prescription or standardized way for anything from queuing systems, to ORMs, file organization and architecture, concurrency outside of web requests and CRUD, etc.
- denverllc 2y ago> But I have such a hard time believing that Node.js is inherently non-performant when there are so many counter-examples of large scale applications that do just fine on it. Like LinkedIn! Except that to make it performant they had to horizontally scale and then restart the server every N hours when they ran out of memory…
- deleted 2y ago[deleted]
- rohan_ 2y agoI'm fairly opinionated about this: 1. I agree, Prisma is not a great ORM. Drizzle is a better choice. It's close to the metal and when the abstraction inevitably leaks, it leaks towards the user using raw SQL 2. Modern JS is extremely performant. Look at any of the benchmarks for the new JS runtimes that have come out in the past 6 months (e.g. Bun / WinterJS / etc...). It approaches Go / Java in terms of performance. 3. Even the traditional NodeJS runtime has been optimized out the ass by Google. For example: JSON parsing has highly performant SIMD instructions under the hood. When a trillion dollar company puts billions of dollars behind a technology it will get fast. 4. There is no possible way that building your CRUD backend in Golang / Rust is a "faster" solution than just using React Server Components. 5. The vast majority of startups are IO-bound, not CPU-bound - so "fast" languages like Go / Rust won't be as relevant. The benefits of Go (for most companies) only apply once your company hits an inflection point and starts to scale and starts to see the throughput that can really take advantage of a lower-level language. If you're building a high-throughput infra company or something, then the things I've mentioned are less relevant.
- aidos 2y agoI only use TS on the frontend, so less opinionated about some of this. I’d love to see some of the codebases where people complain about performance so I could profile them myself. Would put money on being able to improve the situation by orders of magnitude without switching stack. We use Python on the backend of our web app for realtime image recognition and it’s fine because we’ve been thoughtful about data structures and algorithms.
- zer00eyz 2y ago>> We use Python on the backend of our web app for realtime image recognition I have no qualms with python. But Python is the high fructose corn syrup of programing languages... It's in everything. It's dead easy to write out c bindings so from ML to Math to big data tasks it forms the glue to a lot of things. My question is: is your real time image processing IN python or in C that python calls out to?
- 2y ago
- lillecarl 2y agoSounds like you're experiencing BAS, Bad Architecture Syndrome. Application servers should scale out, sure you might need a few more for Node than Rust, but is that really where the issue lies? You wouldn't implement Postgres, Ceph, QEMU or the kernel in Node... But the CRUD part of most applications will be fine in "any slow language"
- mm263 2y agoThis article doesn't really help me choose and based on the title I expected it would. I don't think OP made a "hype" driven decision, but this is certainly one of the most popular modern stacks and what I would like to see instead is a comparison between the popular and less popular options and why OP chose exactly this stack.
- isaacsultan 2y agoMy bias was always to err on the side of popularity. I thought that I would be less likely to encounter frustrating bugs and edge cases using choices that have been battle tested for a least a few years. What I overlooked is that while the platform might be popular and mostly trustworthy (such as Vercel), there are specific solutions like the Vercel Cron Job are still relatively new (released Feb 2023) and still not ready for serious use.
- Kiro 2y agoSeems like this is lacking a lot of crucial stuff. What happens when you want to run a background job?
- isaacsultan 2y agoA true background job would be impossible with this stack. Because I was on the Pro plan, in theory I could set the serverless function timeout to 900s.
- gls2ro 2y ago(shameless plug) I wrote a (biased) article about choosing the tech stack for one of my side projects https://learn.shortruby.com/blog/tech-stack https://learn.shortruby.com/blog/tech-stack It is nothing fancy and I say it is biased because I started with what I know. But I tried to get into details about each choice.
- yoyohello13 2y agoPocketBase + Go + HTMX
- razemio 2y agoPocketbase is just superb. I am using pocketbase together with scalajs and svelte. It saved me so much time setting up the basics and you won't regret it once the project grows. Anything works with pocketbase but go or any js based stack has an easy onboarding.
- joshlemer 2y agoDo you eventually have to move off pocketbase? Looks like it only supports SQLite, and therefor obviously can only run a single server instance. How do you plan to migrate off it in the case that you have higher availability or traffic needs?
- joking 2y agouse a bigger server until the revenue is big enough to justify the migration.
- razemio 2y agoHere are some suggestions if you ever need to scale. https://github.com/pocketbase/pocketbase/discussions/395 https://github.com/pocketbase/pocketbase/discussions/395 Never happened to me. SQLite is faster than most people think. When you hit the limits of sqlite, chances are high that you can afford to use one of the scaling solutions mentioned above. Here are some benchmarks: https://github.com/pocketbase/benchmarks?tab=readme-ov-file https://github.com/pocketbase/benchmarks?tab=readme-ov-file
- joshlemer 2y agoThanks, but here I'm thinking more about availability than anything else. One single instance of a service doesn't seem great
- 2y ago
- davepeck 2y agoTo me this is a valuable write-up because it (a) clearly describes paper cuts accumulated when building with unfamiliar tech and (b) showcases how much nonsense developers are willing to tolerate in the name of "new" or maybe "speed". Some of the paper cuts described include: - Inexplicable interaction between the data layer and a hosting service's environment variable - Migrations that don't work reliably - Cron jobs that don't work reliably - Inexplicable caching behavior for serverless functions, requiring an obtuse workaround - An auth library that makes it hard to... get the ID of the logged-in user, apparently I dunno, I suppose I'm happy to stick with boring old tech.
- isaacsultan 2y agoThanks Dave! That's a great summary of my experience. Most of my experience has been with a more "boring" stack, so I was interested in trying some of the more "hyped" technology choices, to see if I was missing out on anything.
- davepeck 2y agoYeah, makes sense. I’m also in a phase where I get to start a lot of new low-stakes web projects, so I’ve made a point of adopting at least one new-to-me tool for each. I love typescript, and am generally happy with modern front-end tooling, but the node back-end ecosystem drives me bonkers — too many paper-cuts from too many tools along the lines you’ve documented here — and has me regularly retreating back to Python or Ruby land.
- simonbarker87 2y agoNestJS with handlebars SSR templates, htmx, Postgres, containerised running on Google Cloud Run.
- isaacsultan 2y agoI'm interested it HTMX, but for a project like this I couldn't afford to lose out on React's ecosystem of pre-made components where the goal was to ship a professional looking SaaS web-app quickly.
- simonw 2y ago"In many ways, I think I picked a great stack to move quickly and ship things. However, considering all the time spent debugging some of issues that stemmed from using more cutting edge infra providers, next time I'll more carefully consider setting up parts of my infra with a more traditional solution like AWS." That right there is the rationale behind the "Choose Boring Technology" movement: https://boringtechnology.club/ https://boringtechnology.club/
- throwup238 2y agoI can't believe AWS is considered boring technology now. I don't know whether to feel old or cry on my dedicated servers.
- mason55 2y agoIt really depends on which parts of AWS you're using. Spinning up a bunch of EC2 instances and treating them like colo'ed servers has pretty much always been boring (other than the excitement of not having drive to the DC when you need to reboot something).
- skrebbel 2y agoIt’s boring at 2-4x the price of the same boring thing elsewhere though. If you don’t use the E in EC2 then why go with AWS?
- goosejuice 2y agoTend to agree, though I don't always practice it. Boring is also subjective, even if it's a metaphor for mature. The same sort of arguments could be said for "choose what you know", "choose what you understand", "choose what you can hire for", "choose what you can afford".. the list goes on. Like most things in life there are no cheat codes.
- CuriouslyC 2y agoDefinitely would reach for remix before next, and I would go with a big cloud provider container app solution such as Azure container apps (if azure was better) or Google Cloud Run (good, but do you trust google?) before Vercel. Personally I think ORMs are mostly bad and Prisma is more of the same. Zapatos at least gives you typed SQL results without a lot of overhead.
- isaacsultan 2y agoWhy Remix over Next? As for the ORM / query building, did you also consider Drizzle and Kysely against Zapatos?
- CuriouslyC 2y agoNext is buggy, Remix mostly just works, and I have zero interest in Vercel which is the Next selling point IMO. I haven't played with either Drizzle or Kysely, looking at the docs Drizzle in particular looks slimmer and more sql-like which is a plus, though in general I think having an environment like dbeaver or data grip that gives you completions for your queries and developing them there then copy/pasting the code and getting type safety on raw queries with zapatos is still superior for power users who know sql.
- 0xblinq 2y agoAgree with this. Remix is a thousand times better than Next. We migrated our main application to Remix and couldn't be happier. The app router stuff is such a mess.
- omani 2y agoI call my stack GETHAS: Golang + Echo + Templ + HTMX + Alpine.js + Supabase
- angra_mainyu 2y agoWhy Templ? What are the advantages over html/template? It seems to just recreate JSX in Go. I should add, I'm someone who heavily dislikes JSX and prefers SFCs.
- omani 2y agoI wanted to try out Templ and just stuck with it.
- yoyohello13 2y agoTempl gives you type checking and LSP support in your templates.
- Fire-Dragon-DoL 2y agoWhat's echo? It's impossible to look it up on the web
- gmhafiz 2y agohttps://echo.labstack.com/ https://echo.labstack.com/ a Go web framework
- Fire-Dragon-DoL 2y agoThank you!
- isaacsultan 2y agoWhat Supabase functionality are you using? Database, Auth, etc. What has your experience been like with them?
- HumanOstrich 2y ago
- zeroCalories 2y agoVercel is very cool, but I wish we made more progress in technology that is easy to self host than a service.
- 0xblinq 2y agoThat won't happen. That's not a priority for them and goes against their business interests. In fact, there are already many intentional limitations that makes Next a very bad choice if you're self hosting. proof: https://github.com/vercel/next.js/discussions/46722 https://github.com/vercel/next.js/discussions/46722
- deleted 2y ago[deleted]
- jcmontx 2y agoRails/Laravel/Django + Postgres/Mysql + 5 usd/mo DO droplet. Next.
- queuebert 2y agoMore accurate subtitle: "Choosing the Right Tech Stack for a Lightweight Web App". There are way more use cases out there than a simple web or mobile app.
- isaacsultan 2y agoI agree, the context is important here. My use-case was B2B SaaS.
- pmdr 2y agoWhy does 'modern' nowadays mean 'host everything on managed services' like Vercel or Netlify? Why is running your own database so frowned upon? Is *SQL/SQLite so insecure that a default password-protected setup can be pwned within minutes? Managed hosting can give you a head start, but also increased costs. There are quite a few horror stories when it comes to billing.
- lelanthran 2y ago> Why is running your own database so frowned upon? It's a meme that running your own DB means that you'll get owned within seconds of going live, or lose all your data in the first day because fires in your data center are a daily occurence :-/. It's the modern equivalent of "MongoDB is Web Scale". > Managed hosting can give you a head start, but also increased costs. Yeah ... buuuuuuut ... it's a very tiny head start. Sure, you may save a few hours by using a hosted postgres service, but you save that only once over the entire lifetime of the database server! IOW, if you set up a PostgreSQL server on a couple of cheap VPS instances, you can continue using that server for each new product until you hit performance/security problems. I've got exactly one PostgreSQL server set up, and all my little experiments happen on that one server, with me creating new databases as and when needed.
- Keyframe 2y agoif only there was a network stack for it, we could use TempleOS + HolyC as a Lambda in AWS. These things are useless without data or gravitas behind them.
- andyg_blog 2y agoIf this article is to be believed, they are storing user passwords in plaintext.
- willsmith72 2y agonah, it's hashed and salted. otherwise just === not bcrypt compare import { compare } from "bcrypt";
- isaacsultan 2y agoYes, exactly hashed and salted by bcrypt. If I wanted harden this setup, my next consideration would be either having a separate microservice that's purely responsible for auth, or using 3rd party provider like Cognito.
- fallinditch 2y agoFascinating discussion. What I'm looking for in a tech stack for my web app: CRUD - simple requirements at first but could be developed over time to include more social/community functions. Good dev experience, I'm a relative newbie and will be learning on the go. Inexpensive to host, no unexpected bills. My tech stack should have the potential to scale nicely, in case it ever needs it. So I'm not looking for much, just Easy - Powerful - Future Proof Sounds like the OP's stack is not it.
- deleted 2y ago[deleted]
- 0xblinq 2y agoThis is the "Hyped" stack, not the "Right" stack. From all of this, the worst decision is to use Next. Vendor lock in, developed by one of the most shady companies right now, and full of problems.
- isaacsultan 2y agoI've published the 2nd part on this post, covering my front-end stack here: https://news.ycombinator.com/item?id=39919574 https://news.ycombinator.com/item?id=39919574
- 0xblinq 2y agoAuthor's code is vulnerable to timing attacks and probably others as well. This is why people should use established backend frameworks such as Laravel/Django/Rails if they really want to focus on their product and not on reinventing the square wheel.