# How Open-SEO Handles Next.js Routing Without a `pages` Directory

> Discover how Open-SEO manages Next.js routing without a pages directory. This Vite-powered React app defines routes explicitly in web/src/routes for clear control and efficient development.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-08-16

---

**Open-SEO does not use Next.js routing at all—it is a Vite-powered React application that defines routes explicitly in `web/src/routes` rather than using a `pages` directory.**

While you might expect a modern React SEO tool to rely on Next.js file-system routing, the `every-app/open-seo` repository takes a fundamentally different approach. Instead of leveraging the classic `pages/` convention that maps files to URLs automatically, this project opts for explicit route configuration with React Router. Understanding this architectural choice clarifies how navigation, code splitting, and rendering work throughout the codebase.

## Why There Is No `pages` Directory

The most important distinction: **Open-SEO is not a Next.js application**. A quick check of [[`package.json`](https://github.com/every-app/open-seo/blob/main/package.json)](https://github.com/every-app/open-seo/blob/main/package.json) confirms that `next` appears nowhere in the dependency list. Instead, you'll find **Vite** and **React Router** handling all build and navigation concerns.

This design decision trades automatic file-system routing for **explicit control**. Rather than inferring routes from folder structure, developers register each route manually by exporting components from the `web/src/routes` directory. The router then maps these components to specific URL paths at runtime.

## Where Routing Actually Lives: `web/src/routes`

The routing logic centralizes in **`web/src/routes`**, where each route is implemented as a standalone component. Consider the pricing page:

- **File**: [[`web/src/routes/_marketing/pricing.tsx`](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/pricing.tsx)](https://github.com/every-app/open-seo/blob/main/web/src/routes/_marketing/pricing.tsx)
- **URL path**: `/pricing`

The underscore prefix in `_marketing` indicates this route belongs to a logical group—likely sharing layouts, analytics, or meta tag configurations—without affecting the public URL structure. When the application initializes, the router imports these components and builds its internal route table.

This pattern differs sharply from Next.js, where placing [`pages/pricing.tsx`](https://github.com/every-app/open-seo/blob/main/pages/pricing.tsx) would automatically create the same route. Open-SEO's approach requires explicit registration but eliminates surprises from nested folders or dynamic segment conventions.

## Build and Runtime Architecture

Three key files define how this non-Next.js routing stack operates:

| File | Purpose |
|------|---------|
| [[`web/vite.config.ts`](https://github.com/every-app/open-seo/blob/main/web/vite.config.ts)](https://github.com/every-app/open-seo/blob/main/web/vite.config.ts) | Configures the Vite dev server and production build pipeline |
| [[`web/worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/web/worker-configuration.d.ts)](https://github.com/every-app/open-seo/blob/main/web/worker-configuration.d.ts) | Types the Cloudflare Worker handling edge-side rendering |
| `web/src/routes/*` | Contains all routable page components |

Since Vite manages the build, there is no `next dev` or `next build` process. Hot module replacement, code splitting, and asset optimization all flow through Vite's plugin ecosystem. The resulting static files deploy to Cloudflare's edge network, with [[`worker-configuration.d.ts`](https://github.com/every-app/open-seo/blob/main/worker-configuration.d.ts)](https://github.com/every-app/open-seo/blob/main/web/worker-configuration.d.ts) ensuring type-safe environment bindings for any server-side logic.

## Handling SEO Without `getStaticProps` or `getServerSideProps`

Next.js developers rely on data fetching methods tied to the `pages` directory. Open-SEO replaces these with **client-side data fetching** and **Cloudflare Worker edge rendering** where needed.

- For static content, components fetch data directly in `useEffect` hooks or receive props from parent layout components
- For SEO-critical metadata, the `_marketing/` route group likely applies consistent Open Graph and meta tag patterns
- For dynamic rendering at the edge, the configured Cloudflare Worker intercepts requests and can inject server-rendered HTML before the React hydration completes

This architecture achieves SEO parity with Next.js while maintaining full control over the caching and rendering strategy.

## Comparing Next.js vs. Open-SEO Routing Approaches

| Aspect | Next.js `pages` | Open-SEO `web/src/routes` |
|--------|---------------|---------------------------|
| Route discovery | Automatic file-system crawling | Explicit component imports |
| Dynamic routes | `[id].tsx` file naming | Router configuration object |
| Data fetching | `getStaticProps`, `getServerSideProps` | Client-side or Worker-side |
| Build tool | Next.js compiler | Vite |
| Deployment target | Vercel-optimized | Cloudflare Workers edge |

## Summary

- **Open-SEO uses Vite + React Router**, not Next.js, so there is no `pages` directory
- Routes live in **`web/src/routes`** with explicit path-to-component mapping
- The `_marketing/` subgroup organizes related pages without URL prefix changes
- SEO and rendering handle through client-side hydration and Cloudflare Worker edge logic
- [[`package.json`](https://github.com/every-app/open-seo/blob/main/package.json)](https://github.com/every-app/open-seo/blob/main/package.json) confirms zero Next.js dependencies

## Frequently Asked Questions

### Can I migrate Open-SEO to use Next.js file-system routing?

Not without substantial restructuring. The project tightly couples to Vite's build pipeline and React Router's navigation model. Converting to Next.js would require replacing the custom routing layer, adapting data fetching patterns, and migrating the Cloudflare Worker deployment to Next.js's preferred hosting models.

### Why choose explicit routing over automatic file-system routing?

Explicit routing prevents accidental URL exposure when reorganizing code and enables complex route guards, code splitting boundaries, and nested layouts that file-system conventions struggle to express. The tradeoff is slightly more boilerplate when adding new pages.

### How does Open-SEO achieve fast page loads without Next.js optimization?

Vite's aggressive code splitting and pre-bundling, combined with Cloudflare's edge caching, deliver comparable performance. The React Router-based navigation also supports lazy route loading, ensuring browsers only download JavaScript for routes users actually visit.