I first came across Nitro when Nuxt 3 was still in its pre-release stages. I was crazy keen on Nuxt 3 and loved to snoop around the pre-release stuff, trying to understand what in the world was coming. Nitro seemed weird to me with having an API of passing event
to all these random functions, like getQuery(event)
etc, and not accessing everything from a request on a single object. (These came from h3 v1)
Since this first impression with a little bit of confusion, I've learnt to appreciate Nitro for its ability to be deployed anywhere, caching, and straightforward way of doing things.
Deploy Anywhere
Before Nitro, if you wanted to write JS for server-side, you had to plan for where it was going to be run. Cloudflare workers, Lambda, and the edge were really picking up steam, and if you wanted to use them, you'd write and deploy differently than how you'd write for a Node.js server.
I very much remember using Netlify Functions and a functions
folder when I wanted to run something on the edge. I couldn't imagine a server
like express running on the edge.
Nitro changed this for me forever. Now, I just write whatever code I want, chuck it into the server
folder in Nuxt, and away I go. (Yes, sometimes you do have to think it through, but way, way less.)
At the time of writing this, Nitro supports 24 deployment providers, and you can always create your own custom preset.
Caching
I love Nitro's built-in caching. I wish every backend framework had defineCachedFunction
. Caching is a pain. Nitro makes it much less of a pain than it could be.
export const cachedGHStars = defineCachedFunction(async (repo: string) => {
const data: any = await $fetch(`https://api.github.com/repos/${repo}`)
return data.stargazers_count
}, {
maxAge: 60 * 60,
name: 'ghStars',
getKey: (repo: string) => repo
})
Isn't that sick!
Don't think there is a project in which I don't use defineCachedFunction
or defineCachedHandler
.
A Straightforward Way
Want an api endpoint, put it in the api
folder. Want a utility, put it in utils
. Want to return a JS object and have it converted to JSON... Just do it.
nitro-app/
├── server/
│ ├── routes/
│ ├── api/
│ ├── utils/
│ └── plugins/
├── nitro.config.ts
├── tsconfig.json
└── package.json
Nitro uses the H3 utils. It took a little getting used to, but there's a straightforward function for everything. I.e., to get the query:
export default defineEventHandler((event) => {
const query = getQuery(event); // { key: "value", key2: ["value1", "value2"] }
});
H3 v2 is around the corner. So the above API will look different soon.
Conclusion
I've heard it said that abstractions are usually going to get in your way more than they help, but Nitro is my favourite abstraction for doing the opposite of that. It just works! Shout out to the team behind it and especially Pooya Parsa!