Pass small, stable values to Active Job: ids, or Active Record objects that Rails turns into GlobalID references. Keep passwords, tokens and large personal data out of arguments, because job payloads are stored in your queue backend and in failure records, often for longer than you expect.
What Active Job accepts
The Active Job guide lists the argument types supported by default: basic types such as nil, strings, integers, floats, big decimals and booleans, plus symbols, dates, times, durations, hashes with string or symbol keys, arrays, ranges, modules and classes. It also supports GlobalID, which lets you pass a live Active Record object. Rails stores a class and id pair and fetches the record when the job runs.
You can add custom types by defining serializers with serialize, deserialize and klass methods.
Why arguments deserve care
Arguments are written into the queue backend. Depending on the adapter, that might be Redis, a database table or a hosted service. They show up in dashboards, retry lists and backups. If the job fails, adapters typically keep the arguments so it can retry.
Passing a record through GlobalID keeps the payload small and means the job sees current data when it runs. Passing a copy of the data means the job may act on stale values and the queue holds a duplicate of whatever was in them.
| Argument | Good practice |
|---|---|
| Record the job works on | Pass the record, let GlobalID handle it |
| Secret or token | Do not pass it; look it up inside the job |
| Email body or personal data | Pass the id, load at run time |
| Choice of class or module | Never from user input |
| Large blob | Store it, pass a reference |
The row about classes matters. Active Job allows modules and classes as arguments, so a job that accepts a class name from a request and calls methods on it is dangerous. Map user choices to a fixed list on your side.
A review checklist
- Read each job's
performsignature. - Ask what a stranger with read access to the queue could learn.
- Replace secrets with lookups inside the job.
- Replace copied data with ids.
- Check how failures are stored and who can open them.
- Think about deleted records: a job holding a GlobalID for a record that no longer exists will fail when it tries to load it, so decide how to handle that.
- Make sure jobs check authorization when they run, since the user who enqueued them may have lost access by then.
Retries and idempotence
A job that can run twice should be safe to run twice. Charging a card or sending a message needs a guard. That is a reliability point with a security edge, because duplicated actions can be abused.
Quick check
Can I pass an Active Record object to perform_later?
Yes. Active Job supports GlobalID, so Rails serializes a class and id pair and reloads the record when the job runs.
Is the queue private by default?
Treat it as sensitive. Anyone with access to the backend or its dashboard can read stored arguments.
Safeguard's SBOM and dependency scanning cover the gems your job backends rely on, with policy gates on pull requests. A free scan is at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.