---
title: .server modules
---
# `.server` modules
[MODES: framework]
## Summary
Server-only modules that are excluded from client bundles and only run on the server.
```ts filename=auth.server.ts
// This would expose secrets on the client if not exported from a server-only module
export const JWT_SECRET = process.env.JWT_SECRET;
export function validateToken(token: string) {
// Server-only authentication logic
}
```
`.server` modules are a good way to explicitly mark entire modules as server-only. The build will fail if any code in a `.server` file or `.server` directory accidentally ends up in the client module graph.
Route modules should not be marked as `.server` or `.client` as they have special handling and need to be referenced in both server and client module graphs. Attempting to do so will cause build errors.
If you need more sophisticated control over what is included in the client/server bundles, check out the [`vite-env-only` plugin](https://github.com/pcattori/vite-env-only).
## Usage Patterns
### Individual Files
Mark individual files as server-only by adding `.server` to the filename:
```txt
app/
├── auth.server.ts 👈 server-only file
├── database.server.ts
├── email.server.ts
└── root.tsx
```
### Server Directories
Mark entire directories as server-only by using `.server` in the directory name:
```txt
app/
├── .server/ 👈 entire directory is server-only
│ ├── auth.ts
│ ├── database.ts
│ └── email.ts
├── components/
└── root.tsx
```
## Examples
### Database Connection
```ts filename=app/utils/db.server.ts
import { PrismaClient } from "@prisma/client";
// This would expose database credentials on the client
const db = new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL,
},
},
});
export { db };
```
### Authentication Utilities
```ts filename=app/utils/auth.server.ts
import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";
const JWT_SECRET = process.env.JWT_SECRET!;
export function hashPassword(password: string) {
return bcrypt.hash(password, 10);
}
export function verifyPassword(
password: string,
hash: string
) {
return bcrypt.compare(password, hash);
}
export function createToken(userId: string) {
return jwt.sign({ userId }, JWT_SECRET, {
expiresIn: "7d",
});
}
export function verifyToken(token: string) {
return jwt.verify(token, JWT_SECRET) as {
userId: string;
};
}
```
### Using Server Modules
```tsx filename=app/routes/login.tsx
import type { ActionFunctionArgs } from "react-router";
import { redirect } from "react-router";
import {
hashPassword,
createToken,
} from "../utils/auth.server";
import { db } from "../utils/db.server";
export async function action({
request,
}: ActionFunctionArgs) {
const formData = await request.formData();
const email = formData.get("email") as string;
const password = formData.get("password") as string;
// Server-only operations
const hashedPassword = await hashPassword(password);
const user = await db.user.create({
data: { email, password: hashedPassword },
});
const token = createToken(user.id);
return redirect("/dashboard", {
headers: {
"Set-Cookie": `token=${token}; HttpOnly; Secure; SameSite=Strict`,
},
});
}
export default function Login() {
return (
);
}
```