How to choose a technology stack
Choose the stack your team can build and maintain for years, that fits what the product does, and that you can hire for. How we decide, with examples.

Carlos Saldaña
Sep 8, 2026 · 7 min read
The checklist we run on Laravel and React releases, from the pull request to the hour after deploy, with the tests and commands behind each step.

Rainer Rodriguez
Co-founder, Nerdify
Aug 4, 2026 · 8 min read
A software testing checklist is the list of checks a change has to pass before it reaches users. Ours has five stages: the pull request (automated tests and review), the merge to staging (migrations and build), the check on staging (flows, roles, devices), the deploy to production, and the first hour after it.
We use this list on the Laravel, React and React Native products we build and maintain. It is written for a small team that ships often, so it leans on automation and keeps the manual part short enough that people do it every time.
Every change starts as a pull request, and nothing merges until these pass.
Permission tests catch the bugs nobody reports, since a user who can see too much rarely complains. Pest datasets make a role matrix cheap to write:
it('restricts invoice exports by role', function (string $role, int $status): void {
$user = User::factory()->withRole($role)->create();
$this->actingAs($user)
->get('/invoices/export')
->assertStatus($status);
})->with([
'admin' => ['admin', 200],
'billing' => ['billing', 200],
'staff' => ['staff', 403],
'viewer' => ['viewer', 403],
]);Adding a role later means adding one line, and the test tells you if the new role can do something it shouldn't.
Our CI runs on GitHub Actions for most projects. The core of the workflow is short:
name: tests
on: [pull_request]
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
- run: composer install --no-interaction --prefer-dist
- run: npm ci && npm run build
- run: cp .env.example .env && php artisan key:generate
- run: php artisan test --parallelWe add the formatter and static analysis as separate steps so a failure says exactly what broke.
When a change merges, it deploys to staging automatically. Before anyone tests it there, we check the parts that break deploys rather than features.
php artisan migrate --pretend prints the SQL a migration will run without running it. We read that output for anything touching a large table.
Staging is where a person checks what the automated tests can't: whether the feature makes sense, and whether it works with real-looking data.
For the flows that matter most, we automate the click-through with browser tests. Pest's browser plugin runs them on Playwright from the same test suite:
it('lets a player book a spot in a game', function (): void {
$player = User::factory()->create();
$game = Game::factory()->withOpenSpots(3)->create();
$this->actingAs($player);
visit("/games/{$game->id}")
->click('Book a spot')
->press('Confirm booking')
->assertSee('You are booked')
->assertNoJavaScriptErrors();
});Browser tests are slower and more fragile than feature tests, so we keep them for the flows where a failure would stop the business, and we run them before release rather than on every push.
For mobile releases the device matrix replaces the browser check: the oldest iOS and Android versions we support, a small screen, and a test build installed from TestFlight or an internal track on a real device. 1Click's iOS and Android app, for example, goes through separate development, testing and production environments, with unit and end-to-end tests, before each store release.
We keep a short list of five to ten flows that get clicked through before every release.
The deploy itself has a short checklist, and it is the same every time.
If we could keep only one habit from this list, it would be additive migrations. A migration that renames a column breaks the old code the moment it runs, and during a deploy the old code is still serving requests for a few seconds.
The release isn't done when the deploy finishes.
Problems that reach production often show up in this hour, and finding them here beats finding them through a support ticket the next morning.
There is no coverage percentage on the checklist. We have seen suites at high coverage that never assert the thing that matters, and suites with modest coverage that test every permission and every payment path. We would rather review which behaviors have tests than chase a number.
We also don't run load tests before every release. They go on the list for specific changes: a new endpoint the mobile app will call on every launch, a report that scans a large table, or a client expecting a traffic spike from a campaign. For an ordinary feature release, response times in the first hour after deploy tell us what we need to know.
A checklist with 80 items gets skipped. Ours fits on one screen per stage, and we prune it. When an item hasn't caught anything in a long time and is covered by an automated test, we remove it. When a bug reaches production, we ask which item would have caught it, and if none would, we add one.
The list lives in the repository as a pull request template and a release template, so it is in front of the engineer at the moment it matters.
Read also · Product development
Quality assurance in a small product team
Aug 11, 2026 · 7 min read
If you want a team to set up this kind of release process on your product, or to review the one you have, see our consulting services.

Written by
Rainer Rodriguez
Co-founder, Nerdify
Rainer co-founded Nerdify in Managua, Nicaragua, in 2016 and works with the team on the client products it builds and maintains.
Choose the stack your team can build and maintain for years, that fits what the product does, and that you can hire for. How we decide, with examples.

Carlos Saldaña
Sep 8, 2026 · 7 min read
A website security audit reviews code, configuration, dependencies and infrastructure for weaknesses. This is the list we work through, in order.

Rainer Rodriguez
Aug 18, 2026 · 7 min read
Nearshore teams work in or near your time zone. Offshore teams are far away, often half a day ahead. What that changes for cost, speed and how you work.

Carlos Saldaña
Oct 20, 2026 · 7 min read