Ask HN: Simplest stack to build web apps in 2021?

99 points by yblu ↗ HN
I'm looking to build a new app with a frontend, rest API, and server-side rendering. I'd prefer a single batteried framework supporting all of these out of the box.

It's been a while since I can develop from a clean slate and I was hoping web dev in 2021 would be much simpler than what I am used to. However, I spent this entire morning looking at modern frameworks (not going to name them to avoid turning this into a different kind of discussion) and I'm kinda disappointed. They all look complicated and require lots of configs and plumbing to get started.

Any stack/framework that you find simple and joyful to develop with?

188 comments

[ 3.4 ms ] story [ 231 ms ] thread
I'd like to know too, but I think I'm going to be disappointed. Currently using dot net core web api with angular or react. I was thinking about trying to pick up django again, is that still likely to be worthwhile? Have done java spring previously. Node/ express didn't seem to have enough batteries included.
Can you define 'worthwhile'?
1. Does it offer significant technical advantages e.g. easier to learn/deploy/ more powerful/ quicker?

2. Not sure of it's market share, does it attract many jobs and projects and in which sectors?

Thanks

With .NET and React in your toolbelt, you already got easy to deploy, powerful and job market. What else do you want? :P

Could always try out F# if you think the grass is greener out there.

If you already are experienced with Node & Java, I doubt it is worthwhile for you. Just keep gaining experience there, I don't see Django overtaking any market anytime soon. It's a niche compared to others, but there is a lot of work in building microservices and API's. As a junior & freelancer, there is no shortage of work for me. Sectors range from API's to pure backend service & DevOps automation. Purely backend jobs.
Everytime this questions comes up (and it comes up a lot especially on HN), the answer is almost always: start with the Language that you already know and then reverse engineer. For example:

PHP => Symfony or Laravel

Python => Django or Flask

Javascript => Node/Express

Ruby => Rails

Then there are others like elixir/Phoenix etc and then you can do your own in Go etc.

I'd go one more, and say specifically Laravel Livewire. It's a pleasure to use and gives you the flexibility of having a reactive frontend.

I do recommend dipping in Laravel first, before Livewire.

Node/Express != Rails, one is a low-level gives you almost nothing at all. The other is a high-level CRUD based framework.
As an aside (and as a Python/Flask user on several past projects) I'd also recommend taking a look at FastApi. (https://fastapi.tiangolo.com/)

I've not used it in depth yet, but from a poke around the overall design and syntax seem very nicely thought out (much more logical/intuitive than Flask, honestly) and it's very fast.

I like that following the idiomatic pydantic/data class style in the fastapi docs really forces you down the OOP rabbit hole and puts some guardrails around your architecture (unlike flask, where you’re free to shoot yourself in the foot however you want). What I don’t like is that fastapi gives the appearance of being batteries included, but the docs on the batteries tend to just point to example projects/templates that a beginner will look at and think omgwtf is all this shit (e.g. https://github.com/tiangolo/full-stack-fastapi-postgresql)
Something like Next.js for JavaScript would be better. Express is too bare-bones for OP's criteria. It's bring your own batteries. Just trying to choose from all the batteries available is a full-time job.
This is the correct answer.

With the addition of:

C# => .Net Core

More specifically, C# => Blazor using .NET 6.

Their latest web framework running on the latest long-term support version of .NET

Anything wrong with Spring? It seems somewhat intuitive for me for some reason. But I have no experience with the others
In my experience, spring has been intuitive until you need anything slightly custom, or until layers deep configuration / reflection magic bites you. Other thing I didn't like about spring was that documentation was pretty sparse and didn't explain concepts well, it's either some hyper-specific tutorials or reference docs. (There are some good blog posts though, but I couldn't build a comprehensive mental model just following the tutorials). It's still what I reach for when I need to spin up a CRUD API quickly.

Rooting for quarkus to become more mature though. (Recently tried based on someone's recommendation on HN).

Probably use Nest over Express if you want something complete like Rails. Express is pretty barebones, its not much more than a wrapper for Node’s http module.
Nest gives you a structured project with strong conventions. On top of that, their document provides plenty of recipes to get common tasks done quickly (authentication/authorisation, persistence, queues, etc). Very solid framework.
Frontend is what will get you. The kids have decided everything now needs to be compiled and transpiled so you won't be able to avoid the hassle of frontend development. If you want to avoid all of that then Flutter/Dart might be a good option: https://dart.dev/web. But this is just me giving random advice. I tried Dart for a while and it's a nice language, no worse than all the other contenders when it comes to web development.
Flutter is cool but not ready for the web, much as Google wants to label their web support as "stable"
What's missing?
Slow scrolling, is a major issue. Hard to solve.

Flutter is great for native iOS and Android though.

In my experience: performance. Even Google's Flutter apps lag horribly in Firefox and feel slow and wonky in Chromium.

The development framework is pretty nice with the way you can share code between native and web, but the end result is just lacking.

The performance is terrible.
I looked at the flutter gallery and it looks like they just compile everything to js files and paint the widgets on a canvas element. Would be interesting to know if they're investing any effort in different backends like WASM. Would probably solve their performance problems. Canvas is obviously a sensible option for rendering but it looks like it might be another reason why their performance isn't great.
They are actually pretty active on the WASM GC group because yeah I think that is the exact plan in the future to ship Flutter web apps as WASM rather than JS.
That's good news. Looking forward to the performance improvements.
Yup, everything is a constanatly changing fix on top of broken JS and a broken architecture.
> If you want to avoid all of that then Flutter/Dart might be a good option: https://dart.dev/web.

I don't get your point, Dart is also compiled to JavaScript.

It reduces the effort of learning different frameworks for the frontend and the backend. You use one language that includes simple interoperatbility between the frontend and the backend. It will still obviously need to be compiled into a format that browsers can work with but if you're gonna use a framework anyway then Dart/Flutter is a reasonable choice (modulo performance issues as mentioned by others in this thread).
But you could make the exact same argument for plain JavaScript? With the difference that JavaScript is way bigger in the web space.
The point is no one uses plain javascript anymore so if you're going to use some domain specific language with its own build pipeline to generate compiled assets for the browser then Dart/Flutter is no worse than any other javascript framework.
It is worse, because very few people use it, and the performance on the frontend is terrible.
My point is the frontend web stack is already very complicated for no good reason so using Flutter/Dart instead of dealing with webpack or whatever the latest build tool is for frontend web projects isn't that big of a difference.

Dart is very easy to learn so whether a lot of people know it or not is not really an issue. Any competent programmer will be able to learn it in a few days.

And my point is that since you're going to learn a JS-like with build tools, you would better be served by JS or TS instead of Dart, since Dart isn't that popular, the frontend experience is terrible and there's not much choice in terms of backend and libraries.
I've tried js, ts, and dart and dart is a much more pleasant language with simpler tooling than the current js/ts web stack. We can continue going back and forth on this but I don't think we're getting anywhere. My suggestion was to someone that was looking to avoid the main hassles of web development and I suggested Flutter/Dart to simplify the toolchain and not worry about having to pick and choose frontend frameworks and build tools because all of that is baked into Flutter/Dart already.

In my brief experience, learning the language and framework only took a few days and it was much easier than making sense of all the issues with the current frontend web stack. Dart also has JavaScript interop so using libraries written in js is not an issue. [1]

1: https://dart.dev/web/js-interop

If you want a batteries included framework, maybe take a look at ember? [1]

It tries to automate a lot via the ember-data module (which also makes queries automatically, e.g. left/right joins etc) so it shines with its predefined rules, lots of former rails people seem to contribute to its ecosystem these days.

[1] https://emberjs.com

I would advise against ember only because of the very steep learning curve. I wpuod even say that it's a learning wall.
Ember uses most of the classical MVC concepts, so I'd argue that the learning curve is redundant when you come from an MVC world outside web development.

From my personal perspective I'd say that Ember tries to keep the "fatigue" effect as low as possible when comparing it with e.g. what's going on since the React Hooks "refactors" everywhere.

If your app is stateless; FastAPI. Otherwise Django all the way (with some cloud managed SQL, if you are not into hosting it yourself). Remember backups.

Put in on a VM, deploy with Ansible, and call it a day.

Even for stateful apps, I reach for FastAPI now. It's just so expressive. For the "full stack bits" there are plenty of libraries, it's just a little work to stitch them together.

This is my boilerplate: https://github.com/ttymck/fastapi-fullstack-boilerplate

Is it better than Flask for rendering HTML templates?
I'm not sure if you're being disingenuous or not. I use Jinja in both Flask and FastAPI, so it'd be hard to say one is "better" at that single task.
If you want an all-in-one, which it sounds like you do, I'd look into something like Nuxt and VueJS 3[1]

If you don't mind separating them out (which lets you use different tools for your web tier and your middle tier) I'd probably use a combination of a static page driven by VueJS on the frontend and Golang on the backend for the API.

[1]: https://v3.nuxtjs.org/getting-started/introduction

Thanks. I do prefer an all-in-one option so this looks promising. The website says v3 is beta and not ready for "production use". Have you encountered major issues with it?
I'd be tempted to use Blazor if I was starting a new greenfield project and somebody else was paying.
Next.js. It takes care of most of the config for you, and integrates client/server/static/API beautifully under a single roof. Also gives you nice bells and whistles like hot reloading out of the box
Check out RedwoodJS
Thanks. First time I heard of RedwoodJS. I skimmed the home page, looks good so far. The only thing I feel unsure is the use of GraphQL. It seems to require some learning curve and I'm not sure why I need it over plain old Rest API.
NextJS has everything you’re asking for, including handling the API. Super simple to get started with straight out of the box and the docs are great.
Phoenix+Liveview or Laravel+Livewire or Rails+Hotwire/Turbo
I quite liked the recent Remix v1 demo (https://www.youtube.com/watch?v=wsJaUjd1rUo). The way you can get data in and out of react with their loader is great.

I personally am looking into using it (or most probably next.js) with Cloudflare Workers / Durable Objects. Running backend code close to end users is awesome.

Rails. But do Rails 7 (still in alpha but it's on rubygems - it's also super stable, I think the alpha label is simply because DHH hasn't finalized all the changes). Gone is all the webpack JS nonsense (it doesn't have any dependency on Node at all). Hotwire/Turbo/Stimulus is standard. ES Modules/import maps are standard. It's dead simple, almost reminds me of the early days of Rails. But of course it's industrial-strength, better than ever, Ruby is also better than ever.

Edit - to make life extra easy also set it up with Postgres and deploy to Heroku. Everything literally just works.

This is debatable and I'd say absolutely not :)
For OP's criteria it works. It's relatively simple (by today's standards), it's full-stack, has everything out-of-the-box. Getting started is as easy as it gets (in 2021).

What would you choose?

Elixir Phoenix. It’s what rails copied for the Hotwire stuff. With distillery you can compile all of it, css, js, images, html, down to one tarball that you unpack and run as a service placed behind a forward proxy for complex setups or standalone if desired. Plus it’ll blow the doors off a Rails app performance wise, measured in micro not milli seconds, and will deploy on a fraction of the resources. Plus the community is filled with ex rails devs who left ruby for elixir so it has a very familiar feel if you come from Rails.
I'd argue against that. Recently, I tried making a few test apps with Phoenix and Rails to get my feet wet with something different (I write Go, Java and PHP in my day job), and with Phoenix I ran into a few issues getting the environment set up, the guide doesn't seem to be as coherent as the Rails dev guide, and there is no matching the resources available for Rails compared to Phoenix.

It'd be great to see that change over time, but to be honest I'd be more excited to see some movement behind the crystal lang, because I love coding in Ruby. All of my side projects are now being written in Ruby because I don't need something that scales in microseconds, or 10's of milliseconds for that matter, and I feel so much more productive.

Again, I hope I'm proven wrong. I think Phoenix has a lot of potential, but it still has a long way to dethrone Rails.

You'd argue against using a framework for a project because you encountered a few issues (which ones?) setting up the environment, and recommend another one because you love coding in ruby?

Do you realize how biased you sound to be?

He's arguing from his opinions and experiences. Say he is biased, is true but irrelevant. (Water is wet)
The original post literally asked for a framework that's "simple and joyful" to develop in. So subjective (biased) opinions definitely matter on this one...
Not a knock on you but maybe you're too new to Rails too.

I've been using Rails for 10+ years now and setting up a phoenix app is very intuitive. A lot of "oh this is like X in Rails". IME most of the complexity was around JavaScript and that's changed with esbuild.

However it sets up with very similar patterns to Rails. Something I'd expect as it's creators came from Rails. Usually the differences are specific to FP vs OO.

Admittedly coming in from another language especially with an OO background would be harder as it's a smaller community than Rails and doesn't have 10 years of documentation sitting out there. That said documenting elixir code is much easier IMO, so that is sure to change. Also the scope of FP languages requires significantly less documentation IME.

The only thing vs Rails that I have found somewhat needing more attention in Phoenix is SSO integration but it's there and progressing especially with the Phoenix 1.6 changes.

> It’s what rails copied for the Hotwire stuff

It is not. From the outside the end result for the user might be similar, but that's where the similarities end. Elixir's LiveView what I assume you're talking about keeps state on the server, in memory, and sychronizes changes back to the client over a websocket. Hotwire is "stateless" in the sense that no end user state is kept in memory on the server across requests. You can also use most of Hotwire without websockets.

My previous company was using Elixir, and they moved away from it because everything took longer to develop, the ecosystem of libraries was very lacking, the tooling (such as editor support) was terrible, and it was very difficult to hire experienced developers.

Performance wise, I agree, it is faster and you will use less servers. A nice problem to have to be honest.

When I say copy I don't mean implementation but inspiration. They may not have copied it exactly in implementation, it is FP vs OO, but stimulus.js was a direct response to LiveView. I don't think there is anything wrong with that however I welcome any advancement that requires less JS.
If we're talking about inspiration, then maybe it goes the opposite way? Given Turbolinks existed many years before even elixir or phoenix existed. In fact the creator of elixir was a very prominent rails dev.

But I insist, they have almost nothing in common other than maybe the end user result. The approaches they take are architecturally very different and with very different trade offs.

I haven’t used it myself, but Next.js is a popular choice if you want to use React. It’s primarily a front end framework, but can do all of the things you mentioned in your post. But probably not the best if you’re looking for something to build a traditional web app with a database. I think there are comparable frameworks for Svelte if you’d rather use that.

But if you really want a full stack framework or don’t want to deal with fancy JavaScript frameworks, I think you’re better off sticking with Rails/Django/Express or something you’ve probably heard of.

I second NextJS, you get React, SSR, serverless endpoints and a rich ecosystem of integrations. It works great with things like Friebase, Supabase or any regular DB / Redis.
I use NextJS at work and it fits everything the OP wants, I would definitely recommend it especially if you're comfortable with JS or TypeScript already.
Thanks! NextJS is mentioned many times in this thread. I'll definitely check it out.
http://htmx.org + whatever backend you like best
Wait, this looks and feels like a very pragmatic way of making modern websites. How has this not become more popular? What are its cons?
> What are its cons?

Is very pragmatic. That means your whole investment in the arcane ways of JS are dust. Not hipster at all.

---

More seriously, Is of little issues here. You setup and it works, so is not something that lead to "generate content" like other setups.

I found only a significant issue (to me) (https://github.com/bigskysoftware/htmx/issues/596) but then I do something that have never done in long time with a JS library: I poke into the source and fix it myself. Far easier than expected! (ie: The code is plain!)

You return HTML from your "api" endpoint's is the biggest opposition I have found. Can mean additional work when you do want to switch to JSON, as the endpoints end up not being very reusable.

I quite like HTMX myself, although I consider it a tool you use to enhance websites and not something you use to build full blown web apps.

You don't return HTML from API endpoints, you return it from your UI endpoints. You could reuse those for JSON with content negotiation, or have a frontend server+backend server setup where the backend server is also a public API, or some other solution.
Semantics over the name aside, you end up returning small chunks of HTML from newly defined routes that are only useful for your HTMX frontend, hence my usage of API as the interface really only makes sense to the machine and not the user without the rest of the page content.

Yes you could inspect the headers and such to determine what type to return, but the core problem remains, that the HTML in those is not reusable whereas as JSON would be.

How much overhead this is for you depends on your design of course, but it does mean some work might potentially be wasted if you go down the full SPA application later and even if not changing layouts and such might be a pain.

Thanks for HTMX and your essays. Today I was reading HTMX documentation on what to do when we design API-first for a particular project but don't want any of the frontend magic aka SPA. I found immediately that I need to use both json_enc and client-side-templates extensions. Hope I am on the right path.
hi animesh, that would only be the case if you are trying to retrofit htmx on top of an existing JSON API

if it is greenfield development, it is much better to simply return SSR HTML and avoid that complexity

you can join the discord for more immediate help:

https://htmx.org/discord

That makes sense. I didn't think about it that way, but traditional MVC views would do just as well I guess for greenfield work.
> Semantics over the name aside, you end up returning small chunks of HTML from newly defined routes that are only useful for your HTMX frontend, hence my usage of API as the interface really only makes sense to the machine and not the user without the rest of the page content.

Web2py (being phased out by py4web which I haven't tried) made that very easy. If your api is accessed as api/hello.html, it can return HTML. According to the extension, hello.json, hello.csv, hello.txt, hello.pdf, etc. can return the adequate content.

Of course you can always return JSON regardless of the extension, but I found the same endpoints serving different formats very convenient.

And pair with https://tailwindcss.com and you are golden.

Seriously, is super productive this way!

This is really interesting. Assuming I'm willing to trust the author's claim that semantic class names are the reason CSS is hard to maintain, what's the advantage of `<img class="w-32 h-32">` over `<img style="width: 32px; height: 32px;">`?
Less typing, less bandwidth (ab)used.
I'd think the former would typically (depending on how many times the class is re-used) use more bandwidth, if anything, since it still requires the framework to define the `w-32 h-32` class attributes elsewhere using the more verbose identifiers. Plus the overhead for an additional request if that class definition happens in an external style sheet.
I like to think of Tailwind as CSS without the C.

Everything is now all at the same global namespace and all of the issues that people run into with specificity go away in the process.

It’s not my personal choice on how to solve that problem I think shadowDOM via web components are a much nicer option personally but Tailwind has a lot of very enthusiastic fans who seem to enjoy it.

Normally you wouldn't use `w-32` but rather something like `w-8`, that translates to `width: 2rem;`. Same with colors, you would use `bg-red-400`, that happens to translate to `rgba(248, 113, 113)`.

Half of TailwindCSS is a _way_ of using styles, but the other half is almost a theme: a set of margins, paddings, text sizes, colours, etc. that work well together.

Think is like the most "functional" way to do CSS, in contrast with the "OO" way (like bootstrap).

Each class is applied in pipeline.

And ONLY to that tag. This is key. This leads to know, exactly, what are the effects on each tag, making the UI design very readable.

Then, you can customize it, and have a way to generate a VERY small CSS as result (another big advantage!) because the naming is normalized.

In short: Is the "same" but with more structure, predictability and tooling applied.

The more you need to customize, and the more pain you to "reverse" a CSS made by others, the more this make sense.

PETAL (Phoenix, Elixir, Tailwind, Alpine.js, LiveView)
PHP and jquery.
I think many people will think this is a joke answer, but IMHO "server-side language of choice + jQuery" is actually the best answer.

So much can be accomplished with server-side rendering and some jQuery sprinkled on top. (jQuery isn't even strictly necessary with modern vanilla JS, but it's very nice syntactic sugar at the least.)

90% of apps/sites will fit into a basic CRUD/REST document format, which is exactly what server-side HTML served over a RESTful interface was made for. Judicious use of jQuery fills in the front end blanks for all but the most advanced use cases.

The big benefit of this is that you're not locked in to the JS framework-of-the-week once it inevitably becomes either deprecated by its mammoth corporate sponsor who doesn't care about you, or when it's no longer the new hotness and you can't find developers who understand it anymore. jQuery has been around with a largely stable interface for a decade and a half.

The secondary benefit is that you're not including some vast framework with innumerable, inauditable dependencies, requiring special expertise from highly-paid developers, just to put an AJAX button on a webform.

I’ve got nothing against PHP and jquery, but those are not even a full stack, let alone a batteries-included framework.
Nothing against PHP as a language but much against bare PHP as a framework. I really suggest you look into Laravel (or any other PHP MVC framework) instead.
Interesting that Svelte hasn't come up yet. Personally I find it to be the only sane web framework out there. Easy to learn, little boilerplate code, very well structured, very fast. Give it a try!
Svelte is great for creating components to be plugged seamlessly in an already existing site. It was the best solution I found for building components in my Shopify store.
Check this out, hope it can help you:

Easily add highly profitable products to your Shopify store. The new dropshipping tool from lets you add trending products to your Shopify store in minutes. It's the simplest and smartest way to dropship.

https://rebrand.ly/h5v3qsw

I also leave you this free guide, it helped me a lot:

https://rebrand.ly/x0qwcbv

I'd absolutely go for next.js and deploy with Vercel. It's got a huge community, lots of starter templates and enterprisey add-ons. There's stuff to learn but react is easily the most popular frontend framework right now and has the most energy.
How do you do database stuff and auth with Next?
Next.js or a create-react-app project for the frontend, which you can host for free on Azure Static Web Apps.

Azure functions or Google Firebase for the backend.

With this approach you might not need to pay a cent depending on your usage, plus you can take advantage of the large ecosystem of React components. For a "non-serverless" approach, I would set up a VM on Linode and use docker-compose behind nginx.

I would also consider using Cloudflare Workers for the backend and for the static site hosting if it is a simple enough app.
Check out remix.run - it just opened sourced today. Created by Michael & Ryan & Kent C Dodds from React Router.

Plenty of folks who "haven't used a framework, but heard X is great" are missing out on the real deal. Give it a go, you won't regret it!

Thanks. It's funny I saw it on HN a bit after my post. Will check it out.
Counterpoint to the suggestions above, why not try out a no/low code framework like Bubble.io?

I've met a few devs recently that are starting with that for simple CRUD projects even though they could easily spin something up in Rails.

I tried it. It's nice but it feels a bit slower. The usual problem with these things is we're so used to doing everything with plaintext that the mouse based approach feels unwieldy.
Interesting. I didn't even think of this option. Let's say the app will eventually grow beyond simple CRUD, do you think something like Bubble.io can still be easy to build on? Or at that point, one would have to migrate to a more bare metal framework?
Perhaps, although by then you will have likely proven traction and can invest confidently in the future stack knowing your needs. Until then getting up and running quickly could be the way to go.