RAP Draft Handling: Draft Tables and Locking
RAP draft handling lets a Fiori elements user edit a business object across multiple stateless HTTP requests without touching the active table, by staging changes in a generated draft table. The draft row acts as a persistent, session-independent lock. Orphaned drafts from crashed sessions, missing cleanup jobs, and children not enabled for draft are the recurring production failures.
This page covers what RAP draft handling actually is structurally, when it earns its complexity and when it does not, and how it sits between the behavior definition and the Fiori elements object page. The bulk of the content is the failure modes around orphaned drafts, authorization gaps on draft actions, and composition mistakes that leave parent and child nodes in inconsistent states.
Published 16 Sept 2026· 1,450 words
What it is
Draft handling is the RAP mechanism that lets a user start editing a business object instance, walk away from the browser, come back, and resume exactly where they left off, without any changes touching the active table until an explicit activate step. The structural fact behind almost every confusion: every draft-enabled entity gets its own generated draft table, separate from the active table, holding a copy of the instance plus draft administration fields such as a draft UUID and last-changed-by information. The 'lock' a user holds on a record is not a classic ABAP enqueue tied to a dialog work process or an update task. It is a row sitting in the draft table, which survives across stateless OData requests. That is exactly why it needs explicit management through generated actions to edit, activate, discard and resume, and why it can outlive the browser session that created it if nobody calls discard.
When to use it
Draft is the right fit for any Fiori elements object page that needs a distinct Edit mode with Save and Cancel, for objects where validations should only fire at a defined point rather than on every keystroke, and for multi-step edit flows where a user might legitimately need to leave and come back to an unfinished document. It is also useful wherever the UI needs to show other users that a record is currently being worked on. It is the wrong tool for value-help entities, pure reporting or analytical consumption, read-only list apps, and simple master data maintained through a single-shot create or update with no intermediate editing state. Reaching for draft there just adds a second table, extra determinations, and doubled write volume for no behavioral benefit.
How it fits the stack
Draft sits between the EML layer and behavior implementation below it, and the Fiori elements object page above it. The behavior definition declares the object as draft-enabled and the framework generates the draft table and the standard draft actions; the developer wires in draft determine actions and save-prepare validations. Fiori elements consumes the generated Edit, Activate, Discard and Resume actions automatically and renders the corresponding buttons without custom UI5 coding. Draft supersedes older manual patterns where a developer built a shadow buffer or Z-table to hold in-progress edits, and it replaces reliance on classic transactional locks as the sole edit-in-progress indicator. It does not remove classic enqueue locking entirely; the active instance is still protected by a standard lock at the point of activation.
A worked example
A travel booking business object is modeled with a root node for the booking header and a child node for booking items. The behavior definition marks the root 'with draft' and generates the draft table alongside the standard actions. A save-prepare validation checks that the booking has at least one item and that the total price is populated before activation is allowed. A user opens the object page, the framework calls Edit, which copies the active instance into a new draft row with a fresh draft UUID. Every subsequent PATCH from the UI updates the draft row, not the active table. The user adds two booking items, closes the browser, and returns an hour later; Resume reloads the same draft row because it is keyed by draft UUID rather than by session. On Activate, the save-prepare determination runs, the framework copies the validated draft content into the active table and the child table, then deletes the draft rows for both nodes. If the child node had not been enabled for draft, item edits would have written straight to the active table while the header stayed pending, producing a document that is inconsistent between header and items.
How to choose
- Does the UI genuinely need separate Edit and Cancel semantics, or is inline editing enough? Fiori elements flexible column layout with an explicit edit flow effectively requires draft; a simple inline-edit list report does not.
- When should validation actually fire? If keystroke-level validation is wrong for the business process and checks belong at save time, draft gives that boundary through early and final validation hooks; if validation is always immediate, draft adds no value.
- How much abandonment risk does the process tolerate? Documents that users routinely start and never finish will accumulate orphaned draft rows; confirm a cleanup job is scheduled before committing to draft for that object.
- Managed or unmanaged behavior? Draft integrates cleanly with managed scenarios; layering draft on top of unmanaged implementations with legacy code reuse means manually keeping a hand-written buffer synchronized with the framework's draft state, which is expensive to get right.
- What is the concurrency profile? High-volume, high-concurrency documents pay a real cost in doubled storage and extra joins for read consistency; weigh that against a simpler locked-by-user flag if a full edit/cancel UX is not actually required.
- Does the object have children? If so, decide up front whether every child node needs draft enablement, because a child left out of draft breaks the atomicity the whole pattern exists to provide.
Common pitfalls
- A crashed browser tab or expired session leaves a draft row in place with no discard call ever issued; the record then appears locked to every other user until the expiry window passes or someone runs the cleanup job, and testers frequently mistake this for a bug in the behavior implementation.
- The scheduled job that purges expired drafts is never activated in the target system, so draft rows accumulate indefinitely and start showing up in ad hoc queries against the draft table long after the actual edits are irrelevant.
- Authorization checks are written for the active entity's create and update operations but not for the draft actions themselves, so a user can open Edit and see fields populated in draft state despite having no real authority to activate the change.
- A composition parent is marked with draft but one child node is left out; edits to that child commit straight to the active table while the parent is still pending, so a discard on the parent leaves orphaned child changes with no corresponding header state.
- Business validation logic is duplicated across the draft determine action and the final save validation with slightly different rules, so a record passes the early check, gets edited further, and then fails activation in a way that looks inconsistent to the end user.
- Draft round-trips are rarely exercised in ABAP unit tests, so navigation and value-help behavior that differs between the draft and active version of an entity only surfaces once real Fiori elements navigation is tested end to end.
ECC, S/4HANA and clean core
Draft handling is a native part of the RAP and CDS-based Fiori elements stack on S/4HANA and is considerably lighter than the older BOPF-driven draft mechanisms used by earlier generations of Fiori apps. From a clean core standpoint, draft is a standard, framework-generated capability configured through the behavior definition rather than custom code, which keeps it upgrade-safe as long as the draft actions are used through their intended hooks. Building a parallel hand-rolled buffering mechanism to mimic draft behavior, instead of enabling the framework's own draft table generation, is the anti-pattern to avoid; it defeats the point of the feature and creates exactly the kind of custom persistence layer clean core principles are meant to discourage.
Whose problem this is
Development owns the behavior definition draft annotations, the draft table configuration, and the determine and validation logic tied to save-prepare and activation. Architecture decides whether a given business object justifies the extra table and complexity given its edit UX and concurrency profile. Functional consultants define what the edit and approval process should look like, including how long an unfinished draft is expected to remain valid.
Related SAP objects
Reviewed pages this object connects to in the ERPClimb knowledge graph.
Source: ERPClimb — https://erpclimb.com/sap-technical-topics/rap-draft-handlingERPClimb is an independent platform and is not affiliated with SAP SE. Reference pages are written and reviewed by SAP consultants for learning and troubleshooting.