# Vercel CI Hell: Fix Next.js Tests Failing in Production

> Tests pass locally but fail on Vercel? The real fix is one line: NODE_ENV in vitest.config.ts, plus CI-aware timeouts. My 4 wasted hours, condensed. →

## Why do my tests pass locally but fail on Vercel?

When tests work on your machine but die in Vercel's CI, it's usually two environment differences: an incorrect `NODE_ENV` configuration, and timeouts tuned for hardware 5-10x faster than the CI container.

The fast checklist:

1. **Force `NODE_ENV` to `'test'`.** Your `vitest.config.ts` needs `env: { NODE_ENV: 'test' }`. Vercel might default to production mode, which strips out React's testing utilities.
2. **Raise timeouts for CI.** Vercel's CI is 5-10x slower than a local machine. Make timeouts environment-aware: `const TIMEOUT = process.env.CI ? 10000 : 5000;`.
3. **Read the Vercel logs.** Look for the specific tests that fail or crawl. The `actImplementation is not a function` error is often a symptom of the `NODE_ENV` issue.
4. **Mock heavy operations.** No file I/O, no giant test data. Lightweight mocks instead.
5. **Don't blame the libraries yet.** Before assuming version compatibility problems, check your environment configuration. It's the most common cause.

The rest of this post is how I learned each of those the slow way.

## Same code, same dependencies, different results

```bash
# Local
$ pnpm test
✓ All tests pass (181 passed)

# Vercel
❌ Build failed
Error: actImplementation is not a function
```

**Stack**: Next.js 16, React 19, Vitest, Vercel
**Time wasted**: 4 hours chasing the wrong problem
**Root cause**: misunderstanding Vercel's CI environment

## What I thought it was (the embarrassing part)

"React 19 compatibility issue with Testing Library!"

So I built, in order:

- a 125-line patch script for React internals
- a custom Vite plugin for module resolution
- mock files and import redirects

All of it failed on Vercel. All of it unnecessary. Four hours of confident engineering, aimed at a problem that didn't exist.

## The real problem

### Your machine is not Vercel's CI

**Local development:**

- Fast SSD, direct I/O
- Dedicated CPU/memory
- React loads in development mode
- Consistent environment

**Vercel CI:**

- Networked storage (slower I/O)
- Shared container resources
- May default to production mode
- Cold starts every build

The result: operations take 5-10x longer on Vercel.

## The two actual issues

### Issue 1: the environment mode

Vercel wasn't loading React in test mode by default.

The fix:

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  test: {
    environment: 'jsdom',

    // ← Forces React test mode
    env: {
      NODE_ENV: 'test',
    },
  },
})
```

Why this matters: React's development build includes test utilities, and the production build strips them out. Without `NODE_ENV: 'test'`, React loads incorrectly on Vercel.

### Issue 2: resource constraints

CI containers are slower. Operations that feel instant locally time out on Vercel.

The fix:

```typescript
// CI-aware timeout configuration
const TIMEOUT = process.env.CI ? 10000 : 5000

it('resource-intensive test', async () => {
  // test code
}, TIMEOUT)
```

A real measurement from this debugging session:

```typescript
// Creating a 100MB test file
const largeFile = createMockImageFile(
  'large.jpg',
  100 * 1024 * 1024,
  'image/jpeg'
)

// Local: ~500ms
// Vercel CI: ~6-7 seconds (!)
```

## The minimal configuration that works

```typescript
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'

export default defineConfig({
  plugins: [tsconfigPaths(), react()],
  test: {
    environment: 'jsdom',
    setupFiles: ['./src/test/setup.ts'],
    globals: true,
    css: true,

    // Critical for Vercel CI
    env: {
      NODE_ENV: 'test',
    },

    // Global timeout with CI awareness
    testTimeout: process.env.CI ? 10000 : 5000,
  },
})
```

### Environment-aware test timeouts

```typescript
// test-config.ts
export const TEST_TIMEOUTS = {
  FAST: process.env.CI ? 5000 : 2000,
  MEDIUM: process.env.CI ? 10000 : 5000,
  SLOW: process.env.CI ? 30000 : 15000,
}

// In your tests
import { TEST_TIMEOUTS } from './test-config'

describe('Feature', () => {
  it('fast operation', async () => {
    // Quick unit test
  }, TEST_TIMEOUTS.FAST)

  it('file I/O operation', async () => {
    // File processing, small data
  }, TEST_TIMEOUTS.MEDIUM)

  it('complex operation', async () => {
    // Large files, network, heavy processing
  }, TEST_TIMEOUTS.SLOW)
})
```

## The diagnostic checklist for next time

When tests fail on Vercel but pass locally:

1. Check that `NODE_ENV: 'test'` is set in `vitest.config`
2. Read the Vercel build logs for slow tests
3. Add explicit timeouts to resource-intensive tests
4. Use environment-aware configuration
5. Mock expensive operations (file I/O, large data)
6. Do not start by assuming library incompatibility

### Common patterns

```typescript
// ❌ Assumes local environment
it('test', async () => {
  await heavyOperation()
})

// ✅ Accounts for CI differences
it('test', async () => {
  await heavyOperation()
}, process.env.CI ? 15000 : 5000)
```

```typescript
// ❌ Creating real 100MB files
const largeFile = createRealFile(100 * 1024 * 1024)

// ✅ Use lightweight mocks
const largeFile = createMockFile({ size: 100 * 1024 * 1024 })
```

## What four wasted hours taught me

### 1. Vercel CI is not your MacBook

Design tests with CI in mind from the start: containerized builds, shared resources, slower I/O, different defaults.

### 2. Configure explicitly

Don't rely on default behavior. Set `NODE_ENV` explicitly, set timeouts for slow operations, make configs environment-aware.

### 3. Error messages can mislead

`actImplementation is not a function` looked like a React compatibility problem. The actual cause: React loading in the wrong mode due to environment misconfiguration.

### 4. Design for CI from the start

Write tests knowing they'll run on slower infrastructure. Account for cold container starts, networked storage, resource throttling, and shared CPU and memory.

## What makes Vercel's build environment different

**Containerized builds.** Each build runs in an isolated container. Containers share infrastructure resources, and I/O is networked, not local.

**Cold starts.** Containers spin up fresh for each build. No warm filesystem cache, dependencies downloaded every time.

**Resource limits.** CPU/memory throttling, shared infrastructure, different performance characteristics.

**Environment variables.** Different defaults than your local `.env`. `NODE_ENV` might not be what you expect, so configure it explicitly.

## Configure for it. Don't fight it.

Vercel's CI is slower than your machine (5-10x), runs Node.js differently, and needs explicit configuration to behave.

The error message pointed at React. The problem was Vercel's environment. Knowing the difference is the whole fix, and it's a one-line config change once you stop patching React internals.

## Sources

- [Vitest Environment Configuration](https://vitest.dev/config/#environment)
- [Vercel Build Configuration](https://vercel.com/docs/build-step)
- [Next.js Testing Best Practices](https://nextjs.org/docs/testing)

**Related reading:** another afternoon lost to a tool silently ignoring my config: [the misplaced `content.config.ts` that ate my Astro schema fields](/en/blog/astro-content-config-location/).

---

**P.S.** Fought your own round with Vercel's CI? Tell me what the error message claimed and what the problem actually was, on [Twitter/X](https://x.com/garbarok).
