Layers: The Composition API Moment for Nuxt

Discover how the Composition API revolutionized Vue development, transforming how we write, organize, and share reactive logic. Learn how Nuxt's 'layers' feature follows a similar path, enhancing flexibility, reusability, and project structure.

Michael Thiessen
Nuxt 3

Mastering Nuxt 3 course is here!

Get notified when we release new tutorials, lessons, and other expert Nuxt content.

Click here to view the Nuxt 3 course

The Composition API is the biggest thing that’s ever happened to Vue.

If you didn’t live through the transition from Vue 2 to Vue 3, you maybe don’t realize just how important it’s been in shaping how we write Vue (and Nuxt) apps.

It was a big moment that shifted how we think about, organize, and write our apps.

Nuxt also has a similar story, although it’s not nearly as dramatic — you probably haven’t even noticed it happening.

Let me explain what I mean by the “Composition API” moment, and then I’ll show you exactly what’s going on with Nuxt.

Before the Composition API

Vue 2 was an amazing framework (and still is today!).

But writing reactive logic in it could get very tricky, for a couple reasons.

First, we had to organize the logic in a very specific way, according to the Options API. Computed properties went together in one place, reactive data in another, and watchers, lifecycle hooks, and everything else all had their specific places too.

This made it difficult to co-locate features together.

If you were working on the validation logic for a form, you might be jumping around between a method, some computed props, and the reactive data. But because they weren’t in the same spot, you had to scroll back and forth, losing your place every once in awhile.

Not the worst thing, but it added a lot of friction, and made it harder to read and understand your code.

Second, sharing and reusing reactive logic was very difficult.

We had mixins, but Dan Abramov of React fame wrote this seminal article outlining all the ways that mixins caused problems. They stem from a similar place as the fragile base class problem, where changes that seem okay in the base class ripple invisibly through your codebase, and break other parts of your codebase that rely on that base class (or in our case, that rely on the mixin).

So, we tried to avoid mixins.

The next thing to share and reuse code is a pattern that we still use occasionally today — renderless components.

With renderless components we’re using an empty Vue component as a container for our reactive logic. We can attach computed props, methods, and any other reactive logic we want, and then hack our way into using calling that logic in other components.

For more on how this works, I’ll refer you to Tailwind’s Adam Wathan who wrote a fantastic article on this many years ago.

This was okay, but it was awkward and didn’t really completely solve the problem of sharing and reusing logic.

Then, Vue 3 came. And with it, the Composition API.

The Composition API

There was quite a lot of drama when the Composition API first came out. I think this is mostly because it was released before the script setup syntax was ready. Using it inside the new setup function added to the Options API was confusing, and didn’t make the benefits all that obvious.

The community was quite divided, and many thought that Vue had made a huge mistake. Thankfully, time has proven those naysayers wrong — the Composition API is here to stay, and it’s made Vue even better.

But what were those benefits?

Well, if you’re familiar with Vue these days, you likely know them already.

First, we can organize our code exactly like any other Javascript or Typescript that we write. Code for specific features can live together, making our code more readable and easier to work with.

Second, sharing and reuse has become so much easier. Not only can we co-locate code together in the same file, but we can then extract that code into a separate file and make it into a reusable composable (or keep it in the same file as an inline composable).

It spawned projects like VueUse, which is probably the most popular Vue library (every time I ask developers what library is their favourite, their answer is VueUse!).

And it makes complete sense why people love it so much.

Before we had to write all of these small pieces of reactive logic over and over again. Now, we can just import (or auto-import) and use a composable that’s been well-tested.

Things like reactive localStorage, working with IntersectionObserver, or reactively tracking state changes with useRefHistory no longer have to be re-implemented inside of each component that needs them.

This is a huge deal!

The Composition API has unlocked a lot of value for us as Vue developers, and I know you likely agree (though you might prefer the Options API, and that’s okay, too).

Each person we ask on our podcast, Deja Vue, has said they prefer the Composition API over the Options API, usually for this reason. Evan You, who created Vue, said that one of the main benefits of the Composition API is that it lets you use your existing Javascript skills and apply them to reactive logic in Vue.

Okay, by now you should be convinced that the Composition API was a big deal in Vue’s history.

Now, we need to move on to Nuxt.

Nuxt’s Composition API Moment

There’s a feature in Nuxt that gives us a similar benefit, although it’s far less dramatic, and hasn’t shaken and divided the community.

This feature is: layers.

Layers are mini-Nuxt apps that can be combined together to make a larger Nuxt app, like how components can be combined together to create larger Vue components and Vue apps.

It solves the same problems that the Composition API did for Vue.

First, organization.

Before layers, we had to organize our Nuxt apps based on a predefined structure. Components go in one folder, composables in another, server routes in their own folder, and so on. We can’t co-locate based on the feature we’re building or working with. It’s all mashed together and a little disorganized.

Now, with layers, we can create specific layers for each feature of our app.

We can create a blog layer with all of our content, specific composables and components for our blog, as well as any specific app configuration that we need for the blog part of our app. Then we create an auth layer that has all the authentication configuration, API endpoints, and everything else.

When we use these two layers in our Nuxt app, they get deeply merged together, so it’s as if our Nuxt app had all this code to begin with. The difference is that we’re able to put the source code wherever we want — in different directories, in different git repositories, or in different npm packages.

Second, code reusability and sharing.

With layers, because we can stick the source code wherever we want, it’s super easy to share code.

Before layers we had modules, and we still do. But creating a module requires learning a whole new set of things, and is done programmatically. With layers, you can use your existing Nuxt knowledge — and your existing code — and create reusable layers.

Layers let you organize your Nuxt apps however you want. Just like the Composition API does for reactive logic in Vue.

Conclusion

I think layers is a very powerful feature in Nuxt, and I think we’re just scratching the surface on what can be done with it.

It’s a fairly simple feature, but the implications of it — as well as how to use it in the best way — are quite complex.

And although it may not be as huge a turning point for Nuxt as the Composition API was for Vue, I still think it’s a great feature to have.

Michael Thiessen
Michael is a passionate full time Vue.js and Nuxt.js educator. His weekly newsletter is sent to over 11,000 Vue developers, and he has written over a hundred articles for his blog and VueSchool.

Follow MasteringNuxt on