Late 2024, an e-commerce client had this stack: Playwright for browser tests, Postman + Newman for API contract tests. Two CI pipelines, two reporters, two patterns for handling auth, two places to update test data. The Postman license fees were modest but the cognitive overhead of maintaining two systems was significant.
30 days of focused work later, all 240 API tests had moved to Playwright's request fixture. One CI pipeline. One reporter. One auth pattern. License gone, mental overhead gone, regression risk reduced.
This is the migration story — what mapped, what didn't, and the patterns I'd reuse on the next one.
Table of Contents
- Why migrate at all (it's not always worth it)
- What Postman does well that Playwright doesn't
- What Playwright does well that Postman doesn't
- Mapping Postman concepts to Playwright
- The 30-day plan
- Side-by-side code: Postman vs Playwright
- The 5 gotchas that cost me time
- FAQs
Why Migrate at All (It's Not Always Worth It)
Migrate when:
- You're already running Playwright for browser tests and want to consolidate.
- Your Postman tests are written by your QA team (not by external partners who depend on the Postman GUI).
- Your team prefers code-as-tests over GUI-defined tests.
- You have at least 3 weeks of focused QA capacity.
Don't migrate when:
- Your Postman tests are documentation that backend engineers reference.
- Postman Mock Server is critical to your testing workflow.
- You don't have Playwright in production yet.
The e-commerce client's situation matched the "migrate" criteria. They got value. Half my other clients are running Postman just fine; I haven't pushed migration on them.
What Postman Does Well That Playwright Doesn't
- GUI-driven exploration. Backend engineers love the request builder. Hard to beat for ad-hoc API exploration.
- Mock servers. Postman's mock server feature has no direct Playwright equivalent.
- Collection sharing across non-coders. Product managers can run a collection. They can't run a Playwright test.
- Pre-request scripts and dynamic variables. Postman's templating is mature.
- Built-in OAuth flows. Postman has nice OAuth helpers. Playwright is more manual.
What Playwright Does Well That Postman Doesn't
- Code review. Tests live in your repo, get reviewed, get versioned.
- Type safety. TypeScript types catch contract drift at edit time, not run time.
- Real test fixtures. Playwright's fixture system is more powerful than Postman's pre-request scripts.
- Programmability. Loops, conditionals, retries — natural in code, awkward in Postman.
- Combined with browser tests. Same fixtures, same auth, same reports. Huge integration win.
- Free. No license tiers.
Mapping Postman Concepts to Playwright
| Postman | Playwright |
|---|---|
| Collection | tests/api/feature/*.spec.ts directory |
| Request | request.get/post/put/delete call |
| Pre-request script | test.beforeEach or fixture |
| Tests tab assertions | expect(...).toBe(...) |
| Environment variables | process.env.X |
| Collection variables | Shared fixture state |
| Newman runner | npx playwright test |
| Postman reporters | Allure, HTML, JSON reporters |
| Mock server | Separate tool (MSW, WireMock) |
The 30-Day Plan
Week 1: Discovery and shared fixtures
- Export the Postman collection as JSON. Read it. Categorize requests by feature.
- Identify shared concerns: auth, base URLs, common request bodies. Build Playwright fixtures for them.
- Pick the 5 simplest requests. Migrate them as proof-of-concept.
Week 2: Bulk migration of contract tests
- Walk through Postman folders systematically. Convert each request to a Playwright spec.
- Skip anything complex (file upload, OAuth, conditional flows). Park them for week 3.
- Update CI to run both old (Newman) and new (Playwright) suites in parallel. Verify same coverage.
Week 3: Complex flows
- OAuth flows. Use Playwright's request fixture with explicit token handling.
- File upload tests.
request.postwith multipart form data. - Sequential dependent requests. Convert Postman's request chaining to native test sequences.
Week 4: Cutover and cleanup
- Compare Newman vs Playwright results for a week. Confirm parity.
- Remove Newman from CI.
- Archive the Postman collection in case backend devs want to reference it.
- Update documentation. Drop the license.
Side-by-Side Code: Postman vs Playwright
Postman
// Pre-request Script:
const auth = pm.environment.get('authToken');
pm.request.headers.add({ key: 'Authorization', value: `Bearer ${auth}` });
// Request: POST {{baseUrl}}/orders
// Body: { "items": [{ "sku": "WIDGET-1", "qty": 2 }] }
// Tests:
pm.test('Status 201', () => pm.response.to.have.status(201));
pm.test('Has order ID', () => {
const json = pm.response.json();
pm.expect(json.id).to.match(/^ord_/);
pm.environment.set('lastOrderId', json.id);
});
Playwright
// fixtures/api.ts
import { test as base } from '@playwright/test';
export const test = base.extend({
authedRequest: async ({ request }, use) => {
const token = await fetchTestToken();
await use({
get: (url: string) => request.get(url, {
headers: { Authorization: `Bearer ${token}` },
}),
post: (url: string, data: any) => request.post(url, {
data,
headers: { Authorization: `Bearer ${token}` },
}),
});
},
});
// tests/api/orders/create-order.spec.ts
import { test } from '../../../fixtures/api';
import { expect } from '@playwright/test';
test('POST /orders creates an order', async ({ authedRequest }) => {
const response = await authedRequest.post('/orders', {
items: [{ sku: 'WIDGET-1', qty: 2 }],
});
expect(response.status()).toBe(201);
const body = await response.json();
expect(body.id).toMatch(/^ord_/);
});
The Playwright version is longer but more readable, type-safe, and integrates with the rest of your test infrastructure.
The 5 Gotchas That Cost Me Time
1. Postman's request chaining is implicit; Playwright's is explicit
Postman lets you read pm.environment.get('lastOrderId') in any subsequent request, even across collections. Playwright doesn't. You either pass values explicitly between tests in the same file, or use a fixture-level state object.
2. Postman has more permissive JSON parsing
Postman tolerates trailing commas, comments in JSON, and other non-strict syntax. Playwright (and the underlying fetch) does not. Some test bodies needed reformatting.
3. Postman's environment scoping
Postman has 4 levels of variable scope (global, environment, collection, local). Playwright fixtures are simpler. Map Postman's scopes to module-level constants, fixture-level state, and test-level state. The conversion is mechanical once you understand the mapping.
4. Newman's HTML reporter
Some teams have built dashboards around Newman's reporter output. Playwright's reporter is different. Either: regenerate the dashboard from Playwright's JSON output, or write an adapter. Plan for this in week 4.
5. Postman Mock Servers
If your team uses Postman Mock Servers as part of integration tests, the migration breaks those. Stand up an alternative (MSW, WireMock, or Prism) before retiring the Postman workspace.
FAQs
What about Bruno or Hoppscotch?
Modern Postman alternatives. If your migration goal is mainly cost or open-source, Bruno is a near-drop-in replacement. If your goal is consolidating with browser tests, Playwright wins.
How do I keep API documentation up to date after migration?
Use OpenAPI/Swagger as your API spec source. Generate Postman collections from OpenAPI for backend devs who like the GUI. Generate Playwright tests for QA. Single source of truth.
What about parallel API tests?
Playwright's fullyParallel: true works for API tests too. Same caveats — make sure tests don't share mutable state.
Can I keep Postman for some tests and Playwright for others?
Yes — see my multi-framework post. The cost is real but legitimate when each tool fits a clear slice.
What about contract testing with Pact?
Different category. Pact tests the contract between two services from both sides. Playwright API tests verify your API behaves as expected from the client perspective. They complement each other.
How do I handle GraphQL?
Same as REST. request.post('/graphql', { data: { query, variables } }). Match on operation name in mocks if needed.
What about WebSocket testing?
Different API entirely. Use page.routeWebSocket for browser-driven WebSocket tests, or a Node WebSocket client for direct testing.
How do I migrate Postman environments?
Map to .env.staging, .env.production, etc. Load via dotenv. Standard Node pattern.
What about Postman's monitoring features?
That's an uptime/synthetic-monitoring use case. Playwright can do this too — schedule the test to run periodically against production with a separate config. But dedicated tools (Pingdom, Checkly) are better here.
Should I migrate API tests before browser tests?
If you're starting Playwright fresh and have Postman already, do API last. Browser tests are higher-leverage early. Migrate Postman once your Playwright skills and infrastructure are solid.
Wrap-Up
Postman → Playwright API migration is a 30-day project that pays back in unified tooling, type safety, and reduced licensing. It's not always the right call — Postman has real strengths around exploration and mock servers — but for teams already running Playwright, the consolidation is worth the migration cost.
If your team is evaluating this migration and wants help scoping the work, that's part of framework engagements. Or book a free call.
Related reading:
Tayyab Akmal
AI & QA Automation Engineer
6 years of catching critical bugs in fintech, e-commerce, and SaaS — then building the Playwright and Selenium automation that prevents them from shipping again.