Skip to main content
v2026.11,610 entries · CC-BY 4.0

Recoding Variables in Stata: recode, replace, and generate

Stata offers three ways to create or change a variable: recode, replace, and generate. Here is the range-rule syntax recode uses, the specific way replace destroys original data, and when each command is the right one.

Ask about Recoding Variables in Stata: recode, replace, and generate

Answers are drawn from this guide and the rest of the CASRAI corpus, with a link to every source.

Answers are AI-generated from CASRAI’s own published pages and can be wrong, so check the linked sources before relying on one; your question is logged without personal data — never sold, never used to train a third-party model — to show us what CASRAI is missing, so please do not type personal or confidential details. How we use this

Written and maintained by CASRAI Editorial Board

Last updated

recode, replace, and generate can all end up changing what a variable holds in Stata, but they differ on the two things that matter most: whether the result lands in a new variable or overwrites an existing one, and whether the transformation logic is range-based or expression-based. recode is purpose-built for regrouping values into categories and defaults to overwriting the variable you give it; replace always overwrites an existing variable by design; generate always creates a new variable but has no range syntax of its own. Picking the wrong one is how a Likert item, an age variable, or a survey code gets silently destroyed mid-analysis.

Three commands, three different jobs

These commands get confused because all three can appear to do the same thing — turn one set of values into another — but they were not built for the same job:

  • recode is a dedicated regrouping command: give it value or range rules and it maps old values to new ones in one call. It is the natural tool for banding a continuous variable, collapsing sparse categories, or reverse-scoring a scale.
  • replace is a general-purpose command that assigns a new value to an existing variable, typically restricted with an if qualifier. It has no concept of “rules” — you write the logic yourself, one if condition at a time.
  • generate is replace‘s counterpart for a variable that does not exist yet: it creates a new variable from an expression, again usually paired with repeated if-qualified statements to build up the full mapping.

The practical question is rarely “which command can do this” — usually more than one can. It is “which one keeps my original data recoverable and my rules least error-prone.” Those two questions are answered differently for each command.

A worked example: banding a satisfaction score

Start with a small dataset of a 5-point satisfaction item collected from six respondents:

. list

     +-----------------------+
     | id   satisfaction     |
     |------------------------|
  1. |  1              2     |
  2. |  2              1     |
  3. |  3              3     |
  4. |  4              5     |
  5. |  5              4     |
  6. |  6              3     |
     +-----------------------+

The goal: collapse the 5-point item into three bands — Low (1–2), Medium (3), High (4–5) — without losing the original satisfaction variable.

recode: range rules, in one call, but the overwrite trap

The general form of a recode call is a variable name followed by one or more parenthesized rules, each mapping an old value (or range of values) to a new value:

recode oldvar (rule1) (rule2) ..., generate(newvar)

For the satisfaction example:

. recode satisfaction (1 2 = 1 "Low") (3 = 2 "Medium") (4 5 = 3 "High"), generate(satisfaction_band)

(6 differences between satisfaction and satisfaction_band)

Three things about that syntax are worth internalising before using recode on a variable you have not already backed up:

  1. Ranges use #/#, not #-#. recode age (18/29=1) (30/49=2) (50/max=3), generate(agegroup) is valid; a hyphen is not range syntax here. min and max are valid endpoints that resolve to the variable’s actual minimum and maximum, which is convenient but means the boundary moves if the underlying data changes.
  2. Values that don’t match any rule are left unchanged, not set to missing. If a rule set only covers 1–5 but the variable also contains a stray 9 (a common “not applicable” code), that 9 passes through untouched into the recoded variable unless a catch-all rule is added: (else=.) or (*=.). This is the most common silent error in a recode call — the output looks complete because nothing errors, but an unhandled code has quietly survived the transformation.
  3. You can attach a value label to a category directly inside the rule, as in the example above ("Low", "Medium", "High") — recode defines and applies the label automatically when generate() is used, saving a separate label define/label values step.

The overwrite trap is the generate() option itself: it is optional, not default. Running recode satisfaction (1 2 = 1) (3 = 2) (4 5 = 3) with no generate() overwrites satisfaction in place, permanently, the moment the command finishes — there is no confirmation prompt. The only way back at that point is reloading a saved copy of the dataset. Treat generate() as effectively mandatory on any recode call you run against data you have not just saved.

generate: full control, no range syntax, and the missing-value gap

Where recode gives you range rules for free, generate gives you none — you build the same three-band variable from scratch using an expression and a sequence of if-qualified statements:

. generate satisfaction_band = 1 if satisfaction = 4 & satisfaction != .

The first line is the gap that trips people up: generate newvar = expr if condition only ever populates observations where condition is true. Every observation where it is false — including any observation with a missing satisfaction value, since a missing value fails every numeric comparison in Stata — gets a missing value in satisfaction_band, silently, unless a later replace line explicitly handles it. This is the inverse of the recode gotcha above: recode‘s failure mode is an unmatched value passing through unchanged; a hand-built generate/replace chain’s failure mode is an unhandled value defaulting to missing. Both are easy to miss because neither one throws an error.

generate earns its place over recode when the new variable is not a simple regrouping of one existing variable — a score built from arithmetic across several variables, or a condition that depends on more than one field (generate at_risk = 1 if age > 65 & comorbidity_count >= 2) is a generate job, not a recode job, since recode‘s rules only ever look at the single variable being recoded.

replace: the command that only ever overwrites

replace has no “safe mode” — by design, it always modifies an existing variable’s values in place:

replace varname = expr if condition

That makes it the right tool for exactly two situations: fixing values within a variable you already know you want to keep editing (correcting a data-entry error, filling in a derived variable you just created with generate, as in the example above), and never the right tool for transforming a variable you still need in its original form. Two specific risks are worth stating plainly:

  • Running replace directly on a raw, original variable is irreversible in the same way recode without generate() is — the prior values are gone from the dataset in memory the instant the command runs, with no built-in undo. The safe pattern is always to generate a working copy first, then replace the copy.
  • An omitted or wrong if qualifier overwrites every observation, not just the ones intended. replace satisfaction_band = 3 if satisfaction >= 4 is not the same statement as replace satisfaction_band = 3 if satisfaction >= 4 & satisfaction != . if there happens to be a coding convention where missing is stored as a large sentinel value rather than Stata’s native missing — a stray satisfaction >= 4 match on an unexpected value silently reassigns it too.

Choosing between the three

Situation Best tool Why
Banding or regrouping one existing variable by value/range recode, with generate() Built-in range syntax and inline labels, in one call
A new variable computed from an expression or multiple variables generate + replace recode‘s rules only see one source variable
Correcting values in a variable you already intend to keep editing replace That is exactly what it is for — just never on the only copy of raw source data
Any of the above on a variable you have not backed up None of them, without preserve first or a saved copy of the dataset All three can destroy the original values with no confirmation prompt

Frequently asked questions

Does recode work on string variables?

No — recode‘s rules operate on numeric values. A string variable needs to be converted with encode first (which also assigns the underlying numeric codes a value label), and the resulting numeric variable can then be recoded normally.

What happens if I run recode twice on the same generate() target name?

Stata refuses, the same as any other command that would create a variable that already exists — you get an “already defined” error rather than a silent overwrite. Drop the variable first (drop satisfaction_band) or add the replace option to the generate() call itself if you are intentionally redoing the recode.

Is there a way to preview a recode before committing to it?

Wrap the command in preserve and restore: run preserve, then the recode, then tabulate oldvar newvar to check the cross-tabulation matches intent, then restore to discard the change and rerun it for real once it looks correct. This is the same non-destructive-preview pattern documented for the collapse command in Stata, since neither command has a built-in preview mode.

How does this compare to recoding in SPSS?

The underlying decision is identical — write the recoded result to a new variable rather than overwriting the source — but the mechanics differ. SPSS separates this into two distinct menu commands, Recode into Same Variables vs. Recode into Different Variables; Stata’s recode is a single command where the same choice is made by including or omitting the generate() option.

Related reading

Once a variable is recoded, labelling the resulting categories clearly matters for anyone reading the output later — see labelling variables and values in Stata for the full label define/label values workflow beyond the inline labels shown above. For the statistical reason a banded variable behaves differently from a continuous one in a model, see levels of measurement. For choosing Stata over the alternatives in the first place, see CASRAI’s SPSS vs. Stata comparison and R vs. Stata comparison. For the broader landscape of tools covered here, see the Research Tools & Software hub.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →

Regulatory Radar

Stop finding out after the fact

$29/month, cancel anytime. Daily digest updates from our analysis, a dashboard holding the same items, and a cited assistant for everything they raise.

  • Federal Register, Federal Register+, Grants.gov, Regulations.gov, NSF News, UKRI, plus CASRAI’s own published content.
  • 44,322 indexed passages, and every answer cites the ones it drew on.