This is how we did it at mailchimp. I think this is ignored or overlooked because this means devs might have to care a bit more about operations or the company has to care more.
Database per tenant - barring configuration errors to a connection string or something along those lines - means you won’t ever accidentally leak over other customers data
With Row level security, as good as it is, there is always a chance of leaking happening, due to bugs, user error or the like
Database per tenant also makes migrations safer, and allows easier versioning of an application, for example if you run a SaaS you may put your V2 application into permanent maintenance mode and allow existing customers to use it in perpetuity, while upgrading customers and new customers are put on the V3 platform. This is infinitely easier in practice when the database is per tenant
Many of our clients eventually want to host our app on-premises, so moving it to an on-premises environment is quite easy with the database-per-tenant approach. Just copy the database as is.
>> With Row level security, as good as it is, there is always a chance of leaking happening, due to bugs, user error or the like
That’s not correct. It’s hard isolation. In effect, RLS automatically applies a where clause preventing developers inadvertently accessing the wrong data.
If you don’t set the Postgres environment variable then no data is returned.
All the hard isolation without the schema sync pain.
> In effect, RLS automatically applies a where clause preventing developers inadvertently accessing the wrong data.
Right, but this assumes that you have a) remembered to enable RLS for every table where it matters and b) configured appropriate rules perfectly for every table. And there are tons of things you can mess up in the rules.
With per-tenant instances none of those things can happen.
With a more straightforward approach, the tool can be reproduced with just a few queries in ClickHouse.
1. Create a table with styles by authors:
CREATE TABLE hn_styles (name String, vec Array(UInt32)) ENGINE = MergeTree ORDER BY name
2. Calculate and insert style vectors (the insert takes 27 seconds):
INSERT INTO hn_styles WITH 128 AS vec_size,
cityHash64(arrayJoin(tokens(lower(decodeHTMLComponent(extractTextFromHTML(text)))))) % vec_size AS n,
arrayMap((x, i) -> i = n, range(vec_size), range(vec_size)) AS arr
SELECT by, sumForEach(arr) FROM hackernews_history GROUP BY by
I am continually impressed with Laravel. I have been using Django since 2008 and if I were starting a simple CRUD app I would consider Laravel before Django if I didn’t need anything Python specific. And with sqlc I would probably pick Go over both if I was forced to have a SPA pattern.
I warn everyone away from next.js. Unsurprisingly V0 has a real shot at massively increasing its adoption because people don’t know any better.
What are some salient counter points for choosing next.js? I see a lot of new devs not want to have to think about deployment and management of systems so that is one aspect. If you only know react I guess getting SSR without having to learn something else is a win at the cost of complexity in your codebase.
I've been building SPA apps for years with express and React. For a recent project we decided to use Next.js and self host. The biggest benefits have been
1) having the middleware contained in the same runtime and therefore not having to set up multiple projects and hosting for each. We just build a single docker image and put it in ECS.
2) having things like routing, bundling, linting, etc. already included. There are some downsides--like I would rather have biome out of the box than prettier/eslint, but most the developers haven't really cared.
There is a lot of magic and complexity under the covers that I haven't fully groked, and from that perspective I have reservations about it, especially after the recent CVE. As an example of the complexity, I had to set up Sentry, and while Sentry does have a package specifically for next.js, it was still tricky to ensure we were capturing errors with appropriate context in every possible spot.
It's possible as our project matures we'll hit some roadblocks that will make us question our decision to use next.js and self host, but overall our dev team has been productive with it.
>What are some salient counter points for choosing next.js? ... If you only know react I guess getting SSR without having to learn something else is a win at the cost of complexity in your codebase.
Well there are alternatives to Next.js that handle SSR. Remix for example. That's a popular one.
For a smaller project I wouldnt be afraid of rolling your own with Vite. It's pretty simple.
And for any developer I'd really recommend implementing SSR yourself with an express server or whatever. It really increases your understanding of how frameworks work.
Remix unfortunately does not have (built-in) static export. Plus, the big rename that Remix is now "react-router" does not help their brand. Lot of people don't associate react-router with being a SSR framework.
> Maybe people should rediscover the joys of just FTPing files on a cheap host.
Trouble is that the reason we got away from that model because applications started to become so bloated by frameworks that it took ages to see them start up, thereby necessitating a bunch of hacks to see them respond in a reasonable amount of time, with that eventually evolving into services like Vercel that try to hide the hacks behind a "just upload it" service.
So, first, people would have to rediscover the joys of not creating monstrosities. But in an age when someone might consider Nextjs... Good luck with that.
Actually, I do exactly that and Next.js does have support for static exports. I write the SPA in React/TypeScript/Next.js and export to static html+js+css+assets. Those I can simply sftp to a target static webhost. All the logic is in a REST backend that is written in .NET/C#.
Unfortunately, Next.js dials back static export support with every major release, but it is still usable to create a 100% SPA with static export.
> But, man, at that point you're bringing a bulldozer (with a super uncomfortable operator's station!) to drive a nail.
I think I do exactly the opposite. Having no SSR but everything be statically exported allows me to get away with cheaper hosting on the backend side (the REST API is on a cheap VPS). Static exported SPA means, the user's browser does all the heavy rendering. Plus, no AI bots or search engines contribute to my server's load.
Additionally, the site is fast. Not sure if you know how Next.js works, but since the initial load is already prerendered and just static html+js, it loads instantly. Then hydration happens in the background, unnoticed by the user and the actually JS takes over. JS+CSS are chunked where possible, and Nextjs employs a neat trick: It pre-loads the js+css for the next page once you mouse hover over a link - whether you click it or not. Also increaes the user-perceived speed. Plus, since all js chunks have its sha1 hash in the filename, they can be served with long caching times (even immutable, so cached forever) - once you loaded the website, recurring visits will be blazing fast.
If you want to try it out, the url is https://lockmeout.online - although I do not use a CDN and host verything on a cheap hetzner VPS - hence loading time might be higher outside europe.
> Having no SSR but everything be statically exported allows me to get away with cheaper hosting on the backend side
Building a static website is very reasonable. Using the monstrosity that is Next.js to build a static website seems like super overkill, and I am not sure it offers a good developer experience to justify it[1].
[1] My experience with it had a need for dynamically driven pages, so it may just be that it's horrid design is only a problem once you move past static page generation.
You confuse a static website with a statically exported webapp. The site I do and posted a link to has a user/login section with lots of interactivity. Plus, there are features like using the webcam for scan QR codes (using a wasm library to read QRcode in JS from a media stream), receiving push notifications (and be a PWA on iOS), generating customizable print cards, etc.
Just having conventions around routing, and a "just works" build & lint is nice to avoid a team bikeshedding their own solutions. (Please don't suggest react-router... which seemingly reinvents itself every couple years).
API routes in same codebase that can use same TypeScript types instead of these typegen tools is really nice too.
I'm very much in the camp of not fiddling with build, routing, hydration, state, etc. as they end up being a distraction from just making the thing you set out to make.
As mentioned on another reply, it is favoured by many SaaS vendors as the only extension framework for their products.
Using something else, means not having support, and spending time yak shaving instead of coding the real solution.
From Java/.NET ecosystem point of view, Next.js is the framework where I feel at home.
I work with agencies that have partner agreements with Vercel/Netlify, which makes it a good option for SaaS products that are in the MACH architecture space.
There is such an exaggeration about the need/utility of SSR. Google is dead for new projects, if one is optimizing their stack based on the easiness for Google to crawl it, I think they are making a terrible architectural decision for no return. Deploying a React/JavaScript app is much easier without Next.JS.
All these languages may work very well for many people for the described use cases.
But one of Scala's strength is versatility. You could use it quite well for all the listed use cases too. With just one language. (Maybe with the exception of system programming -- Scala Native still requires a tracing GC.)
Also, it's worth noting that Scala is more popular/mainstream/supported/has bigger community than Julia, Zig and Elixir / gleam. And if Red Monk is to be trusted, even more than Rust
https://redmonk.com/sogrady/2024/09/12/language-rankings-6-2... That comes with many benefits.
> if you don’t need JVM / Java interop
OpenJDK is also very good, even if it's not a strict requirement to use it. Battle-tested, easily debugable, etc... AOT compilation is possible via GaalVM's native-image.
Or you can try Scala.js or Scala Native (which don't have anything to do with JVM).
>All these languages may work very well for many people for the described use cases.
But one of Scala's strength is versatility. You could use it quite well for all the listed use cases too.
I think that the jack of all trades space is already occupied by C#.
I keep looking for what you claim to be doing. I feel like reality continues to smack me in the face with “no one cares about quality”. I have tried big enterprises. I have tried 8 startups in 18 years. I watch the leaders / founders make the same mistakes over and over.
Anyway - your profile resonates with me. Would love to grab a virtual coffee if you are up for it.
Quality seems completely lost as a goal in any shop. See Demming and Peopleware.
In very general terms: "founder mode" is more often than not toxic because it is taken out of context and used to scapegoat being an asshole. Much like the Steve Jobs worshipping of yesteryear.
Lack of financial oversight by board/investors including founders putting up company money for personal investments including moving money into personal accounts to try and inflate their credit ratings.
Non-VC startup: lack of preparing for a future where income is reduced for a period of time and keeping some amount of business savings around
VC startup: lack of appropriate fund handling given the assumption that the money machine will always be there
Hurting all option holders by removing the ability to exercise early or ruining their exit with poor financial stewardship including down rounds or bridge rounds
Always time to fix it later vs taking the time to plan and execute correctly in the first place. This is a relative scale of time to market and risk to opportunity cost but with the exception of large events like tradeshows or such a few more weeks to get it right is better than hobbling along with literally millions of dollars of technical debt if success is found.
And re:tradeshows - demoware is the name of the game and sales needs to be onboard with eng that demoware is demoware and what to sell ahead of the product
Lack of clear execution plan as product market fit is found and everyone has been acting in "throw shit on the wall to see what sticks" mode
General lack of discipline to keep things orderly as work is done which is a failure to understand systems and second / third order effects. Speed is a lagging indicator not a leading one. Everyone wants more, faster but then fails to slow down to put process in place to facilitate moving faster.
Not growing teams appropriately. Lots of lack of empathy, poor hiring practices, abysmal firing practices. Lots of tolerance of "smart assholes" in small teams when leadership only cares about P/L and so the toxicity grows.
Love to see this! This is something rethinkdb (RIP) got right from the start IMO and I like to see tooling like this available from the manufacturer :)
reply