Rewrite PHP Applications to Go with Spec-First Parity Migration
Need to rewrite a PHP codebase to Go without changing behavior? We deliver end-to-end PHP→Go ports using a spec-first, test-gated process: extract executable specs from your Laravel/Symfony app; auto-generate a parity test suite; implement an equivalent Go service (Gin or Chi; sqlc/sqlx or GORM; go-playground/validator; zerolog/zap); and cut over behind a parity gate. We match routes, validators, middleware, sessions/auth, and database behavior 1:1 until tests pass with byte-for-byte parity on payloads, errors, headers, and status codes. Rollout is safe: shadow traffic, per-endpoint canaries, feature flags, and reversible switches. Typical engagements land in 4–12 weeks with fixed pricing. Deliverables: the parity suite, production-grade Go codebase, CI gates, and a cutover plan—preserving business logic while unlocking Go’s long-lived process model, strong typing, and simple deployments.
Step-by-step: rewrite a PHP codebase to Go (without regressions)
- Inventory and spec:
- Crawl routes/controllers/middleware, validators, views/API responses, Eloquent/Doctrine patterns, queues (e.g., Horizon), and CLIs from Laravel (https://laravel.com) / Symfony (https://symfony.com).
- Derive executable specs: OpenAPI for HTTP, JSON Schemas for payloads, SQL invariants (transaction boundaries, idempotency), and error/header contracts.
- Generate tests and parity gates:
- Build deterministic tests from fixtures and sampled traffic; add property-based edge cases (pagination, locales, encodings, large uploads).
- Enforce exact semantics: status codes (e.g., 422 vs 400), headers, JSON null vs absent, and serialization fidelity; include latency smoke-tests.
- Implement Go in parallel:
- HTTP: Gin (https://github.com/gin-gonic/gin) or Chi (https://github.com/go-chi/chi) on net/http (https://pkg.go.dev/net/http).
- Data: sqlc (https://sqlc.dev) / sqlx (https://github.com/jmoiron/sqlx) for explicit SQL, or GORM (https://gorm.io) where Active Record helps.
- Validation: go-playground/validator (https://github.com/go-playground/validator) with typed DTOs.
- Logging: zerolog (https://github.com/rs/zerolog) or zap (https://github.com/uber-go/zap).
- Queues: asynq (https://github.com/hibiken/asynq); CLIs: Cobra (https://github.com/spf13/cobra).
- Map idioms: PSR-15 middleware (https://www.php-fig.org/psr/psr-15/) → Gin/Chi; Eloquent scopes → typed queries/sqlc; Monolog → zerolog/zap; caching via Redis (https://redis.io).
- Use contexts with deadlines (https://pkg.go.dev/context) and pprof (https://pkg.go.dev/net/http/pprof); wire tracing via OpenTelemetry (https://opentelemetry.io).
- Validate and harden:
- CI blocks merges unless the LEAP test harness passes.
- Fuzz encodings (UTF-8/mbstring), multipart uploads, timezone/locale formatting.
- Security parity: bcrypt/argon2 password_verify compatibility, CSRF semantics, cookie flags, CORS rules.
- Cut over safely:
- Deploy Go beside PHP-FPM (https://www.php.net/manual/en/install.fpm.php); mirror traffic (shadow) and diff responses.
- Canary by route/feature flag; promote when parity/error budgets are clean; decommission PHP incrementally with reversible switches.
Why Go for PHP migrations
- Long-lived processes and connection pooling vs PHP-FPM’s per-request teardown; efficient concurrency via goroutines.
- Strong typing and compile-time checks reduce null/array coercion and shape mismatches common in dynamic paths.
- Single static binaries and simpler containerization; no Composer/runtime extensions to juggle (https://getcomposer.org).
- First-class concurrency and streaming (HTTP/2, gRPC) for parallel I/O and background work.
- Robust observability: context timeouts, pprof, expvar, and OpenTelemetry integrations.
What we port 1:1
- HTTP APIs: routes, controllers, middleware, filters, headers, redirects, caching rules.
- Validation: Laravel FormRequests / Symfony Validators → go-playground/validator with typed DTOs.
- Persistence: Eloquent/Doctrine behaviors (transactions, soft-deletes, scopes) → explicit SQL via sqlc/sqlx or GORM when Active Record helps (https://www.doctrine-project.org).
- Auth/sessions: session IDs, CSRF, cookies, password_hash semantics (bcrypt/argon2), 2FA flows.
- Queues/workers/CRON: Horizon/jobs/events → Go workers (asynq or equivalent), backoff/retry/idempotency intact.
- CLI/tools: artisan/console commands → Cobra-based CLIs with the same flags and exit codes.
Our methodology
1) Scope and spec extraction - Inventory routes, controllers, middleware, Blade/API responses, validators, Eloquent/Doctrine patterns, queues (e.g., Horizon), and CLIs. - Derive executable specs: OpenAPI for HTTP, JSON Schemas for payloads, SQL invariants, and error/header contracts.
2) Test generation and parity gates - Build deterministic tests from fixtures and sampled traffic; add property-based edge cases. - Enforce exact semantics (e.g., 422 vs 400), headers, JSON null vs absent, and serialization fidelity. - Include latency smoke-tests to guard regressions during porting.
3) Parallel Go implementation - Frameworks: Gin or Chi for HTTP; sqlc/sqlx for explicit SQL (or GORM where pragmatic); asynq for queues; Cobra for CLIs. - Idiom mapping: PSR-15 middleware → Gin/Chi middlewares; Eloquent scopes → typed queries/sqlc; Monolog → zerolog/zap; Redis/Memcached equivalents for caching. - Handlers use typed DTOs, contexts with deadlines, and structured logging.
4) Parity validation and hardening - CI blocks merges unless the LEAP test harness passes. - Fuzz encodings (UTF-8/mbstring), multipart uploads, and timezone/locale-sensitive formatting. - Security parity: bcrypt/argon2 verification, CSRF semantics (if retained), cookie flags, CORS rules.
5) Rollout and cutover - Deploy Go beside PHP; mirror traffic in shadow mode and diff responses. - Canary by route/feature flag; promote when parity/error budgets are clean. - Decommission PHP paths incrementally with reversible switches.
Specific PHP concerns we handle
- Eloquent ↔ SQL: replace lazy-loading with explicit joins/sqlc to avoid N+1; preserve eager-loading and soft-deletes.
- Form/type coercion: normalize $_POST/$_GET strings into typed structs; handle enums, decimals (big.Rat/shopspring/decimal), and RFC3339 times.
- PSR-7/PSR-15 equivalence: map Request/Response to net/http; preserve header case-insensitivity, cookies, and multipart upload behavior (PSR-7: https://www.php-fig.org/psr/psr-7/).
- Sessions/auth: session store migration (stateless JWT or Redis-backed), password_verify compatibility (bcrypt/argon2i/argon2id), and identical 2FA UX.
- Encoding/serialization: mbstring assumptions, Unicode normalization, float precision, and consistent 404/422/409 mappings.
Incremental options (when not ready for a full rewrite)
- Strangler-fig: route selected endpoints to Go while PHP serves the rest.
- Shadow traffic and response diffing before switching live reads/writes.
- Bridge PHP↔Go for background tasks or IPC during transition (RoadRunner/Goridge: https://github.com/roadrunner-server/goridge).
Tooling map (examples we use by default)
- HTTP: Gin or Chi on net/http; middleware parity with PSR-15 semantics.
- Data: sqlc/sqlx or GORM; migrations via your existing toolchain or raw SQL.
- Validation: go-playground/validator; DTOs with explicit types.
- Observability: OpenTelemetry, pprof, structured logs via zerolog/zap.
- Queues: asynq; schedulers and workers with retry/backoff/idempotency.
- CI: parity gates that fail on any spec drift (status, body, headers, timing thresholds).
Proof
- sqlite-leap — five SQLite engines generated from one spec: https://github.com/safitudo/sqlite-leap
- semver-leap — 5,632 passing tests across independent implementations: https://github.com/safitudo/semver-leap
- LEAP Protocol — spec-first, test-gated, agent-agnostic: https://github.com/safitudo/leap
Pricing & timeline
- Typical engagement: 4–12 weeks depending on endpoints, jobs, and data layer.
- Fixed-price proposal after a 1–2 day discovery and spec sampling.
- Most PHP→Go migrations land between $40k–$120k, including the parity test suite, Go implementation, traffic mirroring, and cutover support. Priced for outcomes, not hours.
Ready to move from PHP to Go without regressions? Request a scoping call for a no-surprise, fixed-price proposal.
Leap Agentic is distinct from Legacyleap.ai and Impetus Leap AI.
Leap Agentic is distinct from Legacyleap.ai and Impetus Leap AI.