Telerik blogs

See how to build an Angular application with Analog, enjoying a modern, smooth developer experience.

Angular has long been a powerful framework for building robust web applications. And now, with Analog, you can enjoy a more streamlined developer experience and modern full-stack capabilities comparable to frameworks like Next.js and Nuxt.

In this article, we’ll explore how to build full-stack applications with Analog, covering everything from file-based routing to server-side rendering. If you’re already familiar with TypeScript and Angular, you’ll find Analog to be a natural and powerful extension of what you already know.

What Is Analog?

Analog is a full-stack meta-framework built on top of Angular. It brings modern features like file-based routing, API routes, server-side rendering and more to the Angular ecosystem. Think of it as Angular’s answer to Next.js or Nuxt.js—a framework that extends Angular to make building full-stack applications more intuitive and developer-friendly. The server and deployment integrations are powered by Nitro.

Setting Up an Analog Project

Getting started with Analog is straightforward. Let’s create a new project using the create-analog package and your choice of package manager (this tutorial uses npm).

Open your terminal and run the command npm create analog@latest my-analog-app. You’ll be asked how you’d like your application to be bootstrapped. Pick Full-stack Application, and select No for Analog SFC and Tailwind.

shows a GIF walk through of creating a new Analog application

Let’s follow the CLI prompt to install and run the application we just created. The following commands will help us do that:

# Navigate to the project directory
cd my-analog-app

# Install dependencies
npm install

# Start the development server
npm run dev

This starts your app with a development server running at http://localhost:5173.

running demo of the current application code. It's a UI with a counter button which increases as you click on it.

File-Based Routing in Analog

One of Analog’s standout features is file-based routing, which simplifies the way you organize and navigate between pages in your application.

In Analog, every file in the src/app/pages directory that ends with .page.ts becomes a route in your application. The route path is determined by the file path:

src/app/pages/
├── index.page.ts              -> /
├── about.page.ts              -> /about
├── users/
│   ├── index.page.ts          -> /users
│   └── [id].page.ts           -> /users/:id (dynamic route)
└── blog/
    └── [...slug].ts      -> /blog/* (catch-all route)

It’s possible to define nested routes in two different ways:

  1. By nesting the route files in folders – src/app/pages/about/team.page.ts defines an /about/team route.
  2. By using the dot notation in the filename – src/app/pages/about.team.page.ts also defines an /about/team route.

We currently have pages/index.page.ts, which renders the homepage you saw earlier. Let’s add an /about page. Add a new file about.page.ts to the pages directory and paste the code below in it:

import { Component } from "@angular/core";
import { RouterLink } from "@angular/router";

@Component({
  standalone: true,
  imports: [RouterLink],
  template: `
    <h1>About Us</h1>
    <p>We are building a full-stack application with Analog!</p>
    <a routerLink="/">Back to Home</a>
  `,
})
export default class AboutPageComponent {}

Notice how we’re exporting the component as the default export. This is how Analog identifies the main component for each route. If your dev server is still running, navigate to localhost:5173/about to see it working.

There is more to file-based routing than I’d like to cover in this article. You can learn more about routing in the Analog documentation. It covers more about layout routes, grouping, etc.

Creating API Routes with Analog

Analog makes it easy to create API endpoints that can serve data to the application. These are defined in the src/server/routes directory. API routes are also filesystem-based routing and are exposed under the default /api prefix. Therefore, the file src/server/routes/users.ts will be accessible under /api/users. The prefix can be configured with the apiPrefix parameter passed to the analog vite plugin. For example:

// vite.config.ts
import analog from "@analogjs/platform";

export default defineConfig(({ mode }) => {
  return {
    plugins: [
      analog({
        apiPrefix: "services",
      }),
    ],
  };
});

Let’s make routes to fetch user data. Add a new file, users.ts, to the src/server directory and paste the code below in it:

// Sample user data
export const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
  { id: 3, name: "Charlie" },
  { id: 4, name: "David" },
  { id: 5, name: "Eve" },
  { id: 6, name: "Frank" },
  { id: 7, name: "Grace" },
];

Now, let’s create a route to fetch all users. Add a new file index.get.ts to the src/server/routes/v1/users directory and paste the code below in it:

import { eventHandler } from "h3";
import { users } from "../../../users";

export default eventHandler(() => ({ users }));

This route returns all users. It exports a handler function that will process the user request and return a response. An event handler is a function that will be bound to a route and executed when the route is matched by the router.

Note: The eventHandler function provides a convenient way to create event handlers for HTTP requests. It’s part of the h3 package, which Analog (via Nitro) depends on.

Notice that we added a get suffix to the filename. This is a convention that Analog uses to identify the HTTP method for the route, and it’s optional. When absent, the route will match all HTTP methods.

Let’s create a route to fetch a single user. Create a new file [id].get.ts to the src/server/routes/v1/users directory and paste the code below in it:

import { eventHandler, getRouterParam } from "h3";
import { users } from "../../../users";

export default eventHandler((event) => {
  const id = getRouterParam(event, "id");

  const user = users.find((user) => user.id === Number(id));
  if (!user) {
    return new Response("User not found", { status: 404 });
  }
  return user;
});

Here, we’re using the getRouterParam function to get the id parameter from the route. We then use the find method to find the user with the given id. If the user is not found, we’re returning a 404 response.

You can test the API routes by running the dev server and navigating to localhost:5173/api/v1/users. You should see the list of users. You can also test the [id].get.ts route by navigating to localhost:5173/api/v1/users/1. You should see the user with ID 1.

You can access cookies and add WebSocket support to your API routes, but that’s beyond the scope of this article. We will cover that in an upcoming article.

You can learn more about API routes in the documentation.

Server-Side Rendering in Analog

Server-side rendering (SSR) is a critical feature for web applications. It provides better SEO, faster initial page loads and improved user experience. Analog supports SSR, and it is enabled by default. This means that when you build your application, Analog will generate build artifacts that will be used to render it on the server. You’ll find them in the build/analog/server directory.

You can opt out of SSR by setting the ssr option to false in your vite.config.ts file.

import { defineConfig } from "vite";
import analog from "@analogjs/platform";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  // ...other config
  plugins: [analog({ ssr: false })],
}));

Some dependencies may need additional transforms to work for server-side rendering. You may need to add the package(s) to the ssr.noExternal array in the Vite config if you receive errors related to them. For example:

import { defineConfig } from "vite";
import analog from "@analogjs/platform";

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => ({
  ssr: {
    noExternal: [
      "apollo-angular", // npm package import
      "apollo-angular/**", // npm package import along with sub-packages
      "@spartan-ng/**", // libs under the npmScope inside an Nx workspace
    ],
  },
  plugins: [analog({ ssr: true })],
}));

Hybrid SSR/SSG Support

Analog supports both Server-Side Rendering (SSR) and Static Site Generation (SSG), giving you the flexibility to choose the right approach for each page in your application. You can use a Hybrid approach where some pages are pre-rendered at build time (SSG) and others are rendered on the server (SSR) at request time.

For SSG, Analog pre-renders pages at build time, creating static HTML files that can be served by any static file server. This is great for content that doesn’t change often. To enable SSG for a page, you can use the prerender option in the analog() plugin for Vite. For example:

import { defineConfig } from "vite";
import analog from "@analogjs/platform";

export default defineConfig(({ mode }) => ({
  plugins: [
    analog({
      prerender: {
        routes: async () => ["/", "/about", "/services"],
      },
    }),
  ],
}));

The Power of Vite in Analog

Analog is built on top of Vite, a modern frontend build tool that offers significant benefits. It has become the standard build tool for many frontend frameworks. It’s used in Remix, Solid Start, Tanstack Start and many more. You get the following features from Vite:

  1. Lightning-fast development server: Vite uses native ES modules to serve your code during development, resulting in instant server start-up and blazing-fast hot module replacement (HMR).
  2. Optimized production builds: When it comes time to build for production, Vite uses Rollup to create highly optimized bundles. However, the Vite team is working on a new bundler called (Rolldown) that will replace Rollup in the future.
  3. Rich plugin ecosystem: You can leverage the growing ecosystem of Vite plugins to extend Analog’s capabilities. There are plugins for CSS (e.g., Tailwind CSS), Markdown rendering and more. If you use Nuxt or Nitro, you’ll be familiar with some of the Vite configuration you saw earlier.
  4. Out-of-the-box support for TypeScript, JSX, CSS and more.
  5. First-class SSR support: Analog leverages Vite’s SSR capabilities to provide a seamless experience for server-side rendering.

The integration with Vite means your development workflow is much faster and more enjoyable. You’ll also benefit from the extensive ecosystem of Vite plugins, which can be used to enhance your application’s functionality.

Conclusion and Next Steps

In this article, we’ve explored how Analog brings modern full-stack capabilities to the Angular ecosystem. We’ve covered:

  • Setting up an Analog project
  • Using file-based routing for cleaner navigation
  • Creating API routes for backend functionality
  • Implementing server-side rendering for better performance and SEO
  • Leveraging hybrid SSR/SSG for flexible rendering strategies
  • Taking advantage of Vite’s powerful development experience

Analog represents an exciting evolution for Angular development. It brings many of the developer experience improvements that have made other meta-frameworks so popular while still leveraging the robust architecture that Angular is known for. I didn’t go deep into the details of Analog’s features, but I hope this overview has piqued your interest. I’ll be releasing more content on Analog in the coming weeks, so stay tuned!

Head over to the Analog documentation to learn more.


Peter Mbanugo
About the Author

Peter Mbanugo

Peter is a software consultant, technical trainer and OSS contributor/maintainer with excellent interpersonal and motivational abilities to develop collaborative relationships among high-functioning teams. He focuses on cloud-native architectures, serverless, continuous deployment/delivery, and developer experience. You can follow him on Twitter.

Related Posts

Comments

Comments are disabled in preview mode.