Trying to pick the best tech stack in 2025 is very hard, especially with all the new frameworks that are getting released.
It's more than just type safety. You also need good performance, scalability, developer experience (DX) and decent community so you don't get stuck.
Today, we will learn why Next.js (frontend) and Encore.ts (backend) might just be the best full-stack combination for modern developers.
Let's jump in.
What is covered?
In a nutshell, we are covering these topics in detail.
- Why this tech stack is a solid choice.
- A step-by-step guide on how to get started with Next.js and Encore.
- Some real-world examples with source code.
Note: Encore is an open source backend framework for TypeScript and Go. In this guide, when I say Encore, I'm talking about the TypeScript version (Encore.ts).
1. Why this tech stack is a solid choice.
There are tons of awesome tech stacks out there and some of them are seriously impressive.
From what I’ve found, pairing Next.js for the frontend with Encore.ts for the backend is a winning combo.
In case you’re new to it, Encore is a backend framework and toolset that comes with a Rust runtime, API validation, integrated infrastructure, a developer dashboard and much more.
We will look at this stack through five main factors:
- Type Safety
- Performance
- Developer Experience (DX)
- Scalability
- Extra benefits
⚡ Type Safety
Whenever you are building a production-level application, it's always better to be type-safe (even if you can work without it).
Encore has a built-in type validation and it's all done in a way, that it's fully declarative which allows it to automatically parse and validate the incoming requests. It makes sure that it matches the schema with no boilerplate.
In short, it validates stuff before it even hits that javascript layer.
Both Next.js (with TypeScript) and Encore.ts enforce static type checking, reducing runtime errors and making code easier to refactor. Encore.ts schema-first approach makes sure that API contracts remain consistent.
Encore also makes your infrastructure type-aware and removes the need for connection strings or other boilerplate.
⚡ Performance
Next.js
: With built-in features like server-side rendering (SSR), static site generation (SSG), automatic code splitting, image optimization, lazy loading, script optimization, cache, serverless functions, link optimization... (and much more), it's safe to say that performance is not a concerning factor while choosing Next.js as frontend.
There is a really nice blog on Optimizing Build Performance in Next.js by Turing.
Encore.ts
: It has a very high-performance Rust runtime, achieving up to 9x the request throughput compared to Express.js and 2x compared to Fastify. It does this by providing multi-threading in Rust, and handling many operations like request validation in Rust instead of JavaScript.
As per benchmark code on GitHub, Encore.ts in terms of cold startup times, is over 5x faster than Express and 17x faster than NestJS.
⚡ Developer Experience
Next.js
: It has a decent file system, built-in features like routing, automatic code splitting, hot module replacement and a rich plugin ecosystem, which makes DX a lot better.
Encore.ts
: DX is one of the strong points in Encore, with built-in obserability (distributed tracing, metrics, logging) with a local dashboard, Automatic architecture diagrams (for a real-time overview), API Explorer (for testing your API endpoints), DevOps automation and reducing boilerplate.
Plus deploying your application is also much easier, with as simple as pushing to a git repository, removing the need for manual steps.
⚡ Scalability
Next.js
: It supports dynamic routing, and different rendering techniques like server-side rendering (SSR), static site generation (SSG), incremental static regeneration (ISR), making it useful for large, high-traffic web applications.
I was reading more about it and found an interesting article on How to Build Scalable Architecture for your Next.js Project.
Encore.ts
: It improves the development of large-scale microservices applications by unifying your infrastructure with your application code and automating infrastructure provisioning and DevOps tasks.
Here's a code sample.
import { SQLDatabase } from "encore.dev/storage/sqldb";
// Create the todo database and assign it to the "db" variable
const db = new SQLDatabase("todo", {
migrations: "./migrations",
});
// Then, query the database using db.query, db.exec, etc.
It also provides a visual tool known as Flow
that gives you an always up-to-date view of your entire system, helping you reason about your microservices architecture and identify which services depend on each other and how they work together.
Encore.ts is cloud-agnostic
by default, which means that it provides an abstraction layer over cloud provider APIs to prevent vendor lock-in
. As your requirements evolve, you can adjust the provisioned infrastructure without changing your application code. That is insanely useful!
⚡ Extra benefits
Next.js
: The detailed docs and active community support is the reason so many developers prefer working with Next.js It also has a lot of plugins, tutorials and resources available. You can check Awesome Next.js which has 10k+ stars on GitHub.
Encore.ts
: Encore takes care of cloud infrastructure and DevOps for you. This allows developers to create production-ready backends quickly, using tools like microservices, Postgres, and Pub/Sub, all without the usual complexity and DevOps hassle.
There are more amazing things you can do, so please check Next.js docs and Encore.ts docs.
If you are very new to Encore, I highly recommend watching this official tutorial.
2. A step-by-step guide on how to get started with Next.js and Encore.
In this section, we will be talking about how to get started with Next.js and Encore.ts.
According to the official docs, you can use a starter template to set things up quickly. I’ve followed the same template and you can check it out if you are interested.
Step 1: Installing the Encore CLI
To develop locally with Encore, you first need to install the Encore CLI. This is what provisions your local development environment and runs your Local Development Dashboard complete with logs, tracing and API documentation.
You can use any of the following commands (Linux, Windows, macOS in order).
curl -L https://encore.dev/install.sh | bash
iwr https://encore.dev/install.ps1 | iex
brew install encoredev/tap/encore
They also provide ts_llm_instructions.txt, a set of pre-made instructions to help LLM powered tools like Cursor and GitHub Copilot to understand how to use Encore. It made things a lot easier whenever I had doubts while using Cursor.
Step 2: Clone the repo and create a new application.
First, clone the template repository using the following command.
git clone --depth=1 https://github.com/encoredev/nextjs-starter.git
Then, navigate to the backend directory, install dependencies and create a new Encore application.
cd nextjs-starter/backend
npm install # Install dependencies
encore app init # Create a new Encore application.
During setup, you will be prompted to sign up for a free cloud account. It's completely free so I recommend doing that. You will also need to select a version, I'm choosing TypeScript for this guide.
Make sure you switch to the backend directory
before running encore app init
. I initially forgot so I had to do it again.
Once the setup is complete, you will get the Application ID
and Cloud Dashboard URL
. Just note these as you will need them later.
Step 3: Run your Encore application.
Now, you need to start your encore application inside the backend directory
using the command encore run
.
Go to frontend/package.json
and replace {{ENCORE_APP_ID}}
with your actual Encore application ID. You can also find this ID in encore.app
.
"gen": "encore gen client {{ENCORE_APP_ID}} --output=./app/lib/client.ts --env=local"
Step 4: Generate a new request client
Navigate to the frontend
directory, open a new terminal window and generate a new request client using this command.
npm run gen # Inside the frontend directory
Running this command will generate the request client at (frontend/app/lib/client.ts
) for your application. This enables communication between your frontend and backend.
Before proceeding, make sure the Encore app is running inside the backend
directory. If not, you can restart it using encore run
. Now, run the Next.js frontend as usual.
cd frontend
npm install
npm run dev
Once it's running, open http://localhost:3000 in your browser to see your application in action.
Similarly, you can access http://localhost:9400 to view Encore's local developer dashboard. Here you can see API Explorer
, Service Catalog
, Infra
, Flow
(visual tool), Snippets
and more.
The local dashboard has small demos at the start so you won't get stuck for sure.
Make sure to keep the contract between the backend and frontend in sync by regenerating the request client whenever you make a change to an Encore endpoint.
It can be done by running npm run gen
.
Step 5: Deploying the Backend with Encore Cloud.
I'm assuming you have a GitHub repo with the code changes.
Open your app in the Encore Cloud Dashboard.
Go to your app settings and set the Root Directory
to backend
. It's because the encore.app
file is in the backend directory.
In the integrations, connect your account to GitHub, which will open GitHub where you can grant access to the relevant repositories (s).
Once connected to GitHub, pushing code will trigger deployments automatically.
You can read more about deploying applications with Encore Cloud on the docs.
You can track the deployment progress in the Cloud Dashboard. Once complete, your app will be live in the cloud! 🎉
Step 6: Deploying the Frontend with Vercel.
We will use Vercel for frontend deployment. Just create a new project on Vercel and point it to your GitHub repo.
In the project settings, set the root directory to frontend
.
Once deployed, your frontend should be live!
Handling CORS Issues
Let's talk a little about CORS configuration
too.
If you are running into CORS (Cross-Origin Resource Sharing) issues when calling your Encore API from your frontend then you may need to specify which origins are allowed to access your API (via browsers).
You do this by configuring the global_cors
key in the encore.app
file, which has the following structure:
global_cors: {
// allow_origins_without_credentials specifies the allowed origins for requests
// that don't include credentials. If nil it defaults to allowing all domains
// (equivalent to ["*"]).
"allow_origins_without_credentials": [
"<ORIGIN-GOES-HERE>"
],
// allow_origins_with_credentials specifies the allowed origins for requests
// that include credentials. If a request is made from an Origin in this list
// Encore responds with Access-Control-Allow-Origin: <Origin>.
//
// The URLs in this list may include wildcards (e.g. "https://*.example.com"
// or "https://*-myapp.example.com").
"allow_origins_with_credentials": [
"<DOMAIN-GOES-HERE>"
]
}
You can read the docs for more information on CORS configuration.
In the next section, we will be taking some examples of applications you can build using this tech stack.
3. Use cases and examples with source code.
We can build lots of innovative apps with Encore and Next.js, so let's explore a few that stand out. The first three have source code and the last two are just example ideas you can build.
✅ Building an Uptime Monitor
You can build an uptime monitoring system that notifies you when your website goes down so you can fix it before your users notice.
The app will use an event-driven architecture and the final result will look something like this.
Here is the automatically generated diagram of the backend architecture, where white boxes are services and black boxes are Pub/Sub topics.
You can check the GitHub repository.
✅ URL Shortener
You can build a URL shortener with a REST API
and PostgreSQL database
. It will also help you learn how to create REST APIs with Encore and test your app locally.
In short, you need to implement the /url
endpoint to shorten URLs using randomBytes
for unique IDs. Set up a PostgreSQL database with a migration file to store the original and shortened URLs. Then you need to modify the API to insert data into the database upon shortening a URL.
Next, add an endpoint to retrieve the original URL by querying the database with the short ID. Test the API using the local development dashboard and include a /url
listing endpoint to fetch all stored URLs.
You can check the GitHub repository.
✅ LLM Chat Room
Just to be clear, you don't need a frontend part for this, but it's a good way to improve your knowledge of Encore.
You can create a chat application that integrates Large Language Models (LLMs) like OpenAI's GPT and Anthropic's Claude with chat platforms such as Slack and Discord. It helps you build AI bots with unique personalities that can engage with users.
This is a microservices-based application, with each service handling a specific aspect of the chatbot ecosystem. The services use a combination of Encore APIs, pub/sub messaging and WebSocket communication to orchestrate the flow of messages between chat platforms and LLM providers.
You can check the GitHub repository.
✅ AI Blog Generator
A blog writing assistant that generates articles based on user input, allows editing and publishing as well.
Tech stack:
-
Next.js
for frontend UI with an editor like Tiptap or Lexical. -
Encore.ts
for backend API to handle text generation requests. -
OpenAI API (GPT-4)
for generating article drafts. -
Resend
for email notifications when articles are ready. -
Supabase
for storing drafts and published articles.
Example Flow:
- Users enter a topic and AI generates a draft.
- They edit, refine and publish within the app.
- Email notifications are sent when it's ready.
✅ Notion-style application for collaboration
A simple Notion-like app for real-time collaboration on notes and tasks.
Tech Stack
- Next.js with WebSockets for real-time updates.
- Encore.ts backend with Redis for live data synchronization.
- PostgreSQL for persistent data storage.
- Clerk/Auth.js for authentication.
- UploadThing for file storage (for adding images to notes).
Example Flow
- Users create and share workspaces.
- Live sync across devices with WebSockets.
- Access controls ensure only authorized users can edit.
These should be enough to get you started.
If you're looking for a really nice crash course, you can refer to this video!
To be honest, no tech stack can be perfect but Encore and Next.js is definitely one of the best and recommended way to build full-stack applications.
Let me know if you have any other ideas.
Have a great day! Until next time :)
You can check my work at anmolbaranwal.com. Thank you for reading! 🥰 |
|
---|
Top comments (13)
Nice! Great post as always 👏
Thanks for reading, Bobby! 🙌 Appreciate it.
Encore.ts seems a great framework. I will check it. Thanks for sharing ❤️🔥
Thanks for reading Dilpreet! I was really surprised by how easy the docs are and getting those pre-made instructions for the cursor made life so much easier.
Great post, Anmol 🔥
Thanks Syakir! 🔥 Time to build something nice :)
Great guide Anmol,
Fundamental work! Thanks!
Good article but, ultimately, I must agree in the negative. Considering the number of well established, properly typed, server side languages, TS seems like the worst choice. And with regards to performance and scalability, anything React related is always a poor choice.
Hot take: anyone looking specifically for a “type-safe” stack should avoid JS/TS on the backend, it’s not truly typed!
Similarly anyone looking for reactive stack should avoid react on the frontend since it’s not truly reactive…
Nah, Goth-Stack does it for me
You lost me at next/react… in 2025… I guess if you are looking for the least performant solution with the worst memory then it’s a decent choice.