# Your 250-Line Route Is the Bug (40 Lines or Else)

> Validate, auth, delegate, respond. Business logic leaking into routes is how backends rot. The 40-line rule explained.

Source: https://boringpush.com/blog/thin-routes-law

Every legacy backend has that one infamous 250-line API route.

Input validation.

Permission checks.

Price math.

Three raw database queries.

Email sending.

External webhook calls.

Response shaping.

All crammed into one file nobody can test.

The thin routes law exists to make that architecture unwelcome.

The rule is simple. **If an API route grows past about 40 lines, business logic is leaking.** Push it down to where it can be tested without a web request.

## The four jobs of a thin route

A compliant route does exactly four things.

1. **Validate the input.** Check payload sizes and fields against the limits the project defines.
2. **Check who is asking.** Confirm the session or API token, and check permissions. The same route serves the browser and the command line.
3. **Delegate.** Make exactly one call to the code that does the real work.
4. **Respond.** Return JSON with the right status code.

Notice what is absent.

No direct queries.

No database connection calls.

No email formatting.

No third-party HTTP clients.

A reviewer reads the whole route in under a minute and knows what it does.

## Why it pays off

**Reviews get faster.** A route that fits on a phone screen can be approved from a phone.

**Tests get simpler.** Business logic lives outside the routes, where it can be tested directly, without mocking HTTP requests.

**Changes stay contained.** The blast radius of any change is bounded to the one place that owns that logic.

**Paywalls stay visible.** The access check is the first thing in the route, not buried at line 200.

## Why agents excel with thin routes

When coding agents like Claude Code, Cursor or Antigravity edit a codebase with fat routes, they often break unrelated features, because logic is tangled with the HTTP layer.

Thin routes shrink what the agent has to hold in context.

Routes stay small and readable, which uses fewer tokens. Logic sits in focused places, so an agent can change one thing without touching five. Diffs stay small enough for you to read before you approve them.

## A worked example in words

A route that lets a signed-in user post a feedback request.

The thin version checks who they are.

It checks the title is present and not absurdly long.

It creates the post through the one place that owns posts.

It returns it with a 201.

That is the whole route.

The fat version also formats a welcome email, checks whether the user is on a paid plan, updates a counter, notifies an admin and logs analytics.

Each of those belongs somewhere else. Moving them out is what makes the route reviewable.

## How to keep a route thin

When a route starts to swell, follow this order.

- Pull validation out into a shared check.
- Pull business logic out into the code that owns that job.
- Pull side effects, like email, into their own steps.
- Keep the route as the four moves and nothing more.

Cut in small steps. Test after each one.

Three small extractions beat one heroic rewrite. If a cut breaks something, you know exactly which one did it.

## What to do on Monday

Pick your three longest routes. Count their lines with a plain line counter.

For each, list the jobs it does.

Extract the biggest job first.

Test the route.

Repeat.

After a week you have shorter routes, clearer ownership and fewer places where a paywall can hide.

## A caveat on the numbers

BoringPush treats 40 lines as a target for new work. Some older routes in the kit are longer, and the project is moving toward the target over time.

Do not copy their size. When a route crosses the line, ask what moved in that should have stayed out.

## Know this first

Forty lines is a target for new work. Some older routes are longer.

The law is a smoke alarm, not a style preference.

## Why BoringPush is the way to do this

Small routes. Clear ownership.

BoringPush holds new routes to four moves.

Validate.

Check access.

Delegate.

Respond.

Reviews get fast. Paywalls stay visible.

## FAQ

### Where does payment webhook verification happen?

In the billing code for each provider. The webhook route receives the raw request, hands it over to be verified and parsed, applies the resulting state change, and returns a 200. The route itself never contains provider logic.

### How do I unit test money logic?

Because the logic sits outside the routes, you can test it directly with plain Node test runners, without booting Next.js or running a local server. The kit's test suite does exactly this.

### Does the law apply to Server Actions?

Yes. Same four movements, same target. Actions sit beside components, which invites UI logic inside them, so the law matters twice as much there.

### What counts toward the 40 lines?

Everything in the file, imports and blank lines included. The crude count is the point, because it settles arguments quickly and cannot be gamed by moving imports around.

### Does it apply to human-written code too?

Yes. Humans rot routes too, just more slowly and with better excuses. Agents write faster, so the structure has to constrain harder.

## Keep reading

- [Thin Routes: Why Agents Fear Your 250-Line Handler](/blog/ai-agents-thin-routes-40-lines) — the agent-side version of this law
- [Build Features With AI That Don't Need Rewrites](/blog/build-feature-with-ai-data-first) — the pipeline this law slots into
- [Protect Pages AND APIs: Your Locked Page Leaks](/blog/protect-page-layout-vs-api-paywall) — the access check that sits first
