---
title: "Importers and baking into editable assets"
slug: /workflows/editable-importers-baking/
markdown: /workflows/editable-importers-baking.md
section: authored
tier: 2
summary: "ScriptedImporter, AssetPostprocessor and bake steps that write inspectable, committed assets instead of hidden runtime state."
sources: ['https://docs.unity3d.com/6000.0/Documentation/ScriptReference/AssetImporters.ScriptedImporter.html', 'https://docs.unity3d.com/6000.0/Documentation/ScriptReference/AssetPostprocessor.html', 'https://docs.unity3d.com/6000.0/Documentation/Manual/class-ScriptableObject.html']
canonical: https://unityworkflowlibrary.dev/workflows/editable-importers-baking/
read_first: /read-first.md
---

> Read first, on every prompt: [non-destructive rules](/read-first.md).

# Importers and baking into editable assets

> ScriptedImporter, AssetPostprocessor and bake steps that write inspectable, committed assets instead of hidden runtime state.

Some content starts outside Unity (a spreadsheet, a JSON level, a model) or is too large to place by hand (a forest,
a road network). Both are fine. What matters is where the result lands: in an asset a human can select and inspect,
not in objects that only exist while the game runs.

## Pick the right tool

| Source of the content | Tool | What a human sees |
|---|---|---|
| A custom file format (`.csv`, `.json`, a level text file) | `ScriptedImporter` | The source file, its importer settings in the Inspector, and the imported objects under it |
| A standard asset that needs consistent settings (models, textures, audio) | `AssetPostprocessor` | The normal importer Inspector, with the enforced values |
| Parameters plus an algorithm (scatter, layout, tables) | An editor bake step | A committed prefab, scene or `.asset` holding the output |
| Content that must differ every session | Runtime generation from authored rules | The rules asset, plus a debug view of each result |

## ScriptedImporter

- **The file is the source, the import is visible.** The
  [ScriptedImporter](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/AssetImporters.ScriptedImporter.html)
  reference describes importers registered with `[ScriptedImporter]` for given file extensions, invoked by the asset
  pipeline to convert those files into assets. A designer edits the source file in their own tool, and Unity reimports
  it.
- **Importer settings are serialized fields.** The same page states the importer's C# fields are serialized like a
  MonoBehaviour's, shown in the Inspector, and control the import per asset. Put scale, defaults and options there,
  not in constants inside `OnImportAsset`.
- **Stable sub-asset identifiers.** Outputs are added with `ctx.AddObjectToAsset(identifier, obj)` and
  `ctx.SetMainObject`. The reference's example notes the identifier must be unique and consistent across imports, and
  that temporary objects not passed to the context must be destroyed. A changing identifier breaks every reference to
  that sub-asset on reimport.
- **Bump the version when output changes.** The first argument of `[ScriptedImporter(version, ext)]` is the importer
  version; change it when the import logic changes so existing assets reimport.
- **Declare dependencies.** When the import reads other assets, implement `GatherDependenciesFromSourceFile`, which
  the reference lists for setting up artifact dependencies and import order.
- **Changing settings from code.** The reference's sequence is `AssetImporter.GetAtPath`, cast to the importer type,
  change values, `EditorUtility.SetDirty`, then `SaveAndReimport`.

## AssetPostprocessor

- **Enforce import rules, do not hide them.** An
  [AssetPostprocessor](https://docs.unity3d.com/6000.0/Documentation/ScriptReference/AssetPostprocessor.html) hooks
  the import pipeline before or after import (`OnPreprocessTexture`, `OnPostprocessModel`, `OnPostprocessAllAssets`
  and others). Use it to apply the project's agreed settings, so the values a human sees in the importer Inspector are
  the ones that ship.
- **Scope by path.** Check `assetPath` and act only on the folders the rule is for. The
  [Assets and serialization](/workflows/assets-serialization/) page records why a postprocessor's path filter is its
  blast radius.
- **Version it.** `GetVersion` returns the postprocessor's version; bump it when its behaviour changes so affected
  assets reimport.
- **Write down what it enforces.** Each postprocessor gets a line in the project's pipeline record (see
  [Recording a content pipeline](/workflows/content-pipeline/)), because a value that silently reverts after a human
  edits it is otherwise a mystery.

## Bake into committed assets

- **BAKE-TO-AN-ASSET (HARD).** A generator that produces content for the shipped game runs in the Editor and writes
  its output to prefabs, scenes or `.asset` files that are committed. The game loads the baked asset. It does not run
  the generator again at startup.
- **Parameters are an asset too.** The generator reads its seed, ranges and rules from a ScriptableObject, so a human
  can change them and press bake again.
- **The output is hand-editable.** After a bake, a human may move, delete or retune individual results. Decide up
  front what re-baking does to hand edits: bake into a separate asset that hand-placed content sits beside, or record
  which entries are locked. Never re-bake silently over hand edits; the
  [Editor tooling](/workflows/editor-tooling/) page requires a tool to name what it would overwrite.
- **Deterministic and diffable.** Same parameters and seed produce the same asset, so a re-bake with no changes shows
  no diff, and a parameter change shows only the entries it really moved.
- **Save through the asset database.** Create with `AssetDatabase.CreateAsset` or `PrefabUtility.SaveAsPrefabAsset`,
  call `EditorUtility.SetDirty` on changed objects, then save. The ScriptableObject Manual page states that edits made
  from script in Edit mode are not saved without `SetDirty`.

## When runtime generation is the right call

- A run that must differ every session (a roguelike layout, a random reward) generates at runtime. Its tables,
  weights and rules are still authored assets, and the generator exposes what it produced (an in-Editor debug view or
  an export to an asset) so a bad result can be inspected and reproduced from its seed.
- Generation that is only there to save an agent from placing things by hand is not a runtime system; bake it.

## Related

- [Authored data assets](/workflows/authored-data-assets/): where the baked output and parameters live.
- Next: [Validation and the authored-system checklist](/workflows/authored-validation-checklist/).
