Backend FAQs

A [small] collection of frequently asked questions related to backend development

How can I deploy my app?

There are several platforms with various tradeoffs that you can use to deploy your app.

A managed host will handle the infrastructure for you. You just need to provide the code and they will take care of the rest. This is the easiest option, but it is also the most expensive if/when you grow out of their free tier.

A VPS (Virtual Private Server) is a virtual machine that lets you run any programs you want. You can set up a proxy like nginx or caddy to serve all your different projects on different domains, and use any database you want (and re-use it in different projects). There are also tools like caprover and coolify that make deploying to a VPS easier.

CloudFlaremanagedserverless$0
DigitalOceanVPSany$5
Fly.iomanagedany$0
GitHub Pagesmanagednone$0
GitLab Pagesmanagednone$0
LinodeVPSany$5
Netlifymanagedserverless$0
Rendermanagedany$0
Vercelmanagedserverless$0
VultrVPSany$2.5

Where can I get a free database?

  • ElephantSQL is just plain vanilla Postgres as-a-service
  • Supabase is a whole backend as-a-service, you can just use the Postgres connection string and none or some of the other stuff they have, which includes a bunch of Postgres extensions like postGIS, super easy oauth authentication with their JS lib which also has a real-time layer over Postgres using logical replication, and it also includes generated http endpoints via postgREST or a graphql api, both of which can leverage Postgres RLS to enforce custom authorization policies
  • Neon is a heavily customized Postgres that de-couples computing and storage, which can later give you the choice to pay for more cpu and less storage or vice versa. they're in "technical preview" though, and i'm guessing their free tier will eventually either downgrade or disappear
  • fly.io has a free tier that includes Postgres and a bunch of other features for deploying your app
  • Amazon RDS has a free tier, but as of writing it only lasts a year

How do I avoid CORS errors and connect my frontend dev server to my backend API?

CORS errors during development happen when your backend is another port than your frontend, and the browser treats this as cross-origin. If your frontend and backend are same-origin (ie on the same host and port) then browsers do not impose CORS restrictions or perform preflight requests, simplifying your backend setup and improving request latency.

Vite

If you are using Vite, in your vite.config.js:


export default defineConfig({
server: {
proxy: {
'/api': 'http://localhost:3000',
},
},
}),

This expects that your api requests include a route prefix, like /api. In express you can do this by adding all of your api endpoints to a Router and then mounting that router at a specific route:


import express from 'express';
const app = express();
app.use(express.json({ strict: true }); // example middleware
const router = express.Router();
router.get('/hello', (req, res) => res.json({ message: 'hello world' }));
router.post('/endpoint', (req, res) => res.json({ received: req.body })));
app.use('/api', router); // make sure this matches your vite config
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`server running on port ${port}`));

create-react-app

create-react-app doesn't have the same restriction as vite, it will simply forward any unknown requests to your backend. You can configure the proxy in your package.json:

package.json

{
//...
"proxy": "http://localhost:3000"
}

You can read more about how CRA handles this in their docs.

webpack-dev-server

If you are using webpack-dev-server directly instead of in a framework, please consult their their docs.

Small front-end changes:

Now make sure all your requests to your backend are using relative URLs rather than including host and port, for example:


-fetch('http://localhost:3001/api/endpoint')
+fetch('/api/endpoint')

Production

For production deployments, you would use nginx to serve your react app and proxy API requests to your backend.

nginx.conf

server {
server_name your-domain.com;
location /api {
proxy_pass http://localhost:3001/;
}
location / {
root /var/www/html/your-domain.com;
try_files $uri $uri/ /index.html;
}
}

JSON Web Tokens or session cookies?

JSON Web Tokens (JWTs) come with several significant drawbacks:

  • Since JWTs are stateless, they contain potentially stale data. If you store a user's role ("admin" or "user") in the token, you will need to issue a new token to update that data.
  • JWTs cannot be invalidated or revoked. They are valid until they expire. This makes it significantly difficult to implement basic security features like demoting an administrator, banning a user, or forcing a user to logout, while maintaining a stateless architecture.

The drawbacks of using a session cookie are:

  • database (or session storage layer) incurs +1 query for every request to ensure session validity and get fresh data.

Given the limitations and drawbacks of JWTs, I think session cookies are a clear winner.

I plan on releasing a post about implementing sessions in node.js soon!

SQL vs NoSQL?

Most application data is relational. It's much easier to use a relational database as your primary data store and offload pieces to other stores if necessary, than to shoehorn relational data into non-relational databases.

The thing that most people seem to overlook when picking document storage is how to manage deleted references. Say you delete a user, and you want to delete all their associated data. In every document db I've seen you'll have to manage that in your application code, and you'll have to hope you don't leave any dangling references. With a relational db it's usually just a case of having on delete cascade on all your foreign keys, and if you miss one the db will yell loudly about maintaining data integrity.

Should I use an ORM for my SQL database?

Personally, no. I have tried many ORMs and none of them offer even remotely comparable performance to plain SQL queries, and they come with a new set of APIs to learn that are only helpful for the simplest scenarios.

Laurie Voss has a great piece written on why ORM is an anti-pattern and I would highly encourage you to read it if you are considering using an ORM.

Query builders (like Knex, Kyseley, etc) are also popular, but in my opinion they just add mental overhead. First, you need to know how to write the SQL query you want, and then you have to figure out how to translate that into the format the query builder wants. I always end up spending more time reading query builder docs than I do formulating the query itself.

Then you must consider that ORMs and query builders are platform specific. If you pick up a new language, you'll end up having yet another new API to learn.

SQL is platform agnostic. It doesn't care if you use JavaScript or Python or anything else, you can send SQL queries from any language and have data returned in a format your application can use.

Learn SQL, if you don't rely on ORMs or query builders to abstract away the details of interacting with your database from you, you will write more performant queries and you will have a better understanding of how to debug slower queries.

Should I store images in my database?

Binary assets that you can't index and search should be stored direct to disk instead of in a database.
Postgres, for example, persists data to disk in pages and blocks, adding an extra layer of abstraction on top of the filesystem's pages and blocks.
Larger entries in a row (eg >2000 bytes) usually get stored in a separate page outside of normal table data, which is a slightly more costly lookup. So storing large binary data in a database becomes a more expensive operation than other types of lookups.
It's better to store those files directly on disk, and then store the file path to those files in the db instead.

Comments