A data access layer, or DAL, is an internal server-only library that decides how data is fetched, checks who is asking, and returns small safe objects called data transfer objects. The Next.js data security guide recommends it for new projects because it puts authorization in one place.
The three approaches in the docs
The guide describes three ways to fetch data:
- HTTP APIs for large existing applications, using a zero trust model and calling existing REST or GraphQL endpoints.
- A data access layer for new projects.
- Component level data access for prototypes and learning.
It recommends picking one and not mixing them. That makes the code predictable for developers and for security auditors.
What a DAL does
Per the guide, a DAL should only run on the server, perform authorization checks, and return safe, minimal DTOs. In the guide's example, a function looks up a profile and then decides field by field what the current viewer may see, returning a phone number only if the viewer is an admin or on the same team.
import 'server-only'
export async function getProfileDTO(slug: string) {
const [rows] = await sql`SELECT * FROM user WHERE slug = ${slug}`
const viewer = await getCurrentUser()
return {
username: rows[0].username,
phonenumber: canSeePhone(viewer, rows[0].team) ? rows[0].phonenumber : null,
}
}
Two details in that pattern are worth copying. The query uses a database API with safe templating, so values are parameters. And the function returns only what this caller needs, not the whole row.
Why prototypes leak
With component level access, a Server Component fetches a full row and passes it to a Client Component as props. Every field then goes to the browser. The guide gives exactly this as an example of exposure: the client component accepts far more data than it needs, which encourages the server component to pass it all down.
Environment variables belong in the DAL
The guide notes that secrets should live in environment variables, and that only the DAL should read process.env, so secrets are not exposed to the rest of the app.
What to check in a review
- Are database packages and environment variables imported outside the DAL?
- Do client components take narrow props rather than whole records?
- Does every function that returns data check the viewer?
- Do mutations go through the same layer?
Quick check
Is a DAL needed for a small app?
The docs suggest it for new projects and call component level access suitable for prototypes. If the app will hold user data, start with the DAL.
What is a DTO?
A data transfer object is a small object holding only the fields a caller is allowed to see.
Sources
Last reviewed: 19 October 2026.