> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ellomas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Recommended patterns for writing reliable, maintainable Replay workflows.

# Best Practices

## Organise Workflows by Domain

Group related workflows in a directory structure:

```
tests/
├── auth/
│   ├── login.yaml
│   ├── registration.yaml
│   └── password-reset.yaml
├── api/
│   ├── crud-users.yaml
│   └── pagination.yaml
└── db/
    ├── seed.yaml
    └── migrations.yaml
```

Run all tests in parallel:

```bash theme={null}
replay run tests/**/*.yaml --concurrency 4
```

## Use Config Profiles for Environments

Never hard-code environment URLs or credentials:

```yaml theme={null}
# replay.yaml
profiles:
  dev:
    config:
      http:
        base_url: http://localhost:3000
      postgres:
        dsn: postgres://dev:pass@localhost:5433/devdb
  staging:
    config:
      http:
        base_url: https://staging.example.com
      postgres:
        dsn: postgres://deploy:pass@staging-db:5432/stagingdb
```

```bash theme={null}
replay run tests/ --profile staging
```

## Extract Early, Assert Often

Extract values as soon as they become available and assert at every meaningful checkpoint:

```yaml theme={null}
- name: login
  type: http
  request:
    method: POST
    url: /auth/login
  extract:
    token: $.data.token
  assert:
    - ["$.status", "eq", 200]
    - ["$.data.token", "not_null"]

- name: get-profile
  type: http
  request:
    method: GET
    url: /profile
    headers:
      Authorization: Bearer {{ token }}
  assert:
    - ["$.data.email", "not_null"]
    - ["$.data.verified", "eq", true]
```

This makes failures easy to pinpoint — you know exactly which step broke.

## Keep Steps Focused

Each step should do one thing well. Avoid steps with multiple responsibilities:

```yaml theme={null}
# Good
- name: create-user
  type: http
  request:
    method: POST
    url: /users
    body:
      email: test@example.com

- name: verify-user-in-db
  type: db
  query: "SELECT id FROM users WHERE email = 'test@example.com'"
  assert:
    - ["$[0].id", "not_null"]

# Bad — mixing concerns in one step
- name: create-and-verify
  type: http
  request:
    method: POST
    url: /users
    body:
      email: test@example.com
```

## Use Deterministic Data

Avoid random values that make tests flaky. When you need unique data, use `{{ nowUnix }}` or a counter:

```yaml theme={null}
- name: create-user
  type: http
  request:
    method: POST
    url: /users
    body:
      email: "qa-{{ nowUnix }}@example.com"
```

## Use `ignore_error` Sparingly

`ignore_error` is useful for cleanup steps or optional checks, but overusing it hides real failures:

```yaml theme={null}
# Good — cleanup that should not fail the pipeline
- name: cleanup
  type: shell
  command: "rm -rf /tmp/test-data"
  ignore_error: true

# Avoid — this hides a real test failure
- name: critical-check
  type: http
  request:
    method: GET
    url: /health
  assert:
    - ["$.status", "eq", 200]
  ignore_error: true  # ← hides failures!
```

## Template Sensitive Data

Use variables for secrets and credentials:

```yaml theme={null}
- name: login
  type: http
  request:
    method: POST
    url: /auth/login
    body:
      email: "{{ API_USERNAME }}"
      password: "{{ API_PASSWORD }}"
```

Pass them via environment variables or the config file — never hard-code them in workflow files.

## Clean Up Test Data

When your workflow creates data, clean it up afterward:

```yaml theme={null}
- name: create-test-data
  type: http
  request:
    method: POST
    url: /users
  extract:
    test_user_id: $.data.id

# ... test logic ...

- name: delete-test-data
  type: http
  request:
    method: DELETE
    url: /users/{{ test_user_id }}
  ignore_error: true
```

## Use `call` for Reusable Steps

Extract common patterns (auth, setup, teardown) into reusable files:

```yaml theme={null}
# auth.yaml
name: login
steps:
  - name: login
    type: http
    request:
      method: POST
      url: /auth/login
      body:
        email: "{{ email }}"
        password: "{{ password }}"
    extract:
      token: $.data.token
    returns: [token]
```

```yaml theme={null}
# test.yaml
steps:
  - name: authenticate
    type: call
    file: auth.yaml
    with:
      email: admin@example.com
      password: "{{ ADMIN_PASSWORD }}"
    returns: [token]
```

## Version Your Workflows with the Schema

Add the JSON schema reference to get IDE autocomplete:

```yaml theme={null}
# yaml-language-server: $schema=https://raw.githubusercontent.com/tomiwa-a/replay/main/schema.json
```

## Run Workflows in CI with `--fail-fast`

In CI, `--fail-fast` saves time by stopping at the first failure:

```bash theme={null}
replay run tests/ --concurrency 4 --fail-fast
```

## What's Next?

* Review the [CLI reference](/replay/cli-reference/index)
* Learn about [configuration](/replay/configuration)
* See [troubleshooting](/replay/troubleshooting) for common issues
