Number ranges enable automatic, unique assignment of numbers for documents, receipts, and other business objects. They guarantee uniqueness even with parallel access.
Number Range Concepts
Concept Description Number Range Object Container for intervals (SNRO) Interval Number range (from-to) Internal Assignment System assigns automatically External Assignment User provides number
Important Transactions
Transaction Description SNRO Maintain number range objects SNUM Maintain number range levels SLG1 Number range log
Basic Examples
Get Next Number
DATA : lv_number TYPE char20,
lv_rc TYPE inri-returncode.
CALL FUNCTION 'NUMBER_GET_NEXT'
nr_range_nr = '01' " Interval number
object = 'ZORDER' " Number range object
number_range_not_intern = 2
WRITE : / 'New number:' , lv_number.
MESSAGE 'Error in number assignment' TYPE 'E' .
Number with Year Dependency
DATA : lv_number TYPE char20,
lv_year TYPE nriv-toyear.
CALL FUNCTION 'NUMBER_GET_NEXT'
toyear = lv_year " Fiscal year
" Result e.g.: 2025-0000001
DATA (lv_doc_number) = |{ lv_year } - { lv_number ALPHA = IN }| .
Get Multiple Numbers at Once
DATA : lv_from_number TYPE char20,
lv_to_number TYPE char20,
lv_quantity TYPE i VALUE 10 .
CALL FUNCTION 'NUMBER_GET_NEXT'
quantity = lv_quantity " 10 numbers
" lv_from_number = first number
" lv_from_number + quantity - 1 = last number
lv_to_number = lv_from_number + lv_quantity - 1 .
WRITE : / 'Number range:' , lv_from_number, 'to' , lv_to_number.
Number with Subobject
" Subobject for cross-client number ranges
CALL FUNCTION 'NUMBER_GET_NEXT'
subobject = 'PLANT1' " e.g., per plant
Read Current Level
CALL FUNCTION 'NUMBER_GET_INFO'
WRITE : / 'From number:' , ls_nriv-fromnumber.
WRITE : / 'To number:' , ls_nriv-tonumber.
WRITE : / 'Current level:' , ls_nriv-nrlevel.
Check Number Range Interval
DATA : lv_percent TYPE p DECIMALS 2 .
CALL FUNCTION 'NUMBER_GET_INFO'
DATA (lv_total) = ls_nriv-tonumber - ls_nriv-fromnumber.
DATA (lv_used) = ls_nriv-nrlevel - ls_nriv-fromnumber.
lv_percent = ( lv_used / lv_total ) * 100 .
WRITE : / 'Utilization:' , lv_percent, '%' .
MESSAGE 'Number range almost exhausted!' TYPE 'W' .
Check External Number Assignment
DATA : lv_extern_number TYPE char10 VALUE '1000000001' .
" Check if number is in valid range
CALL FUNCTION 'NUMBER_CHECK'
nr_range_nr = '02' " External interval
number = lv_extern_number
" Number is valid, now reserve it
CALL FUNCTION 'NUMBER_MARK_AS_USED'
number = lv_extern_number
MESSAGE 'Number is outside the range' TYPE 'E' .
Number Range Buffer
" Buffer for better performance (in mass processes)
CALL FUNCTION 'NUMBER_RANGE_ENQUEUE'
" Get numbers from buffer (faster)
CALL FUNCTION 'NUMBER_GET_NEXT'
CALL FUNCTION 'NUMBER_RANGE_DEQUEUE'
Reset Number Range Level (Caution!)
" Only for test systems - NEVER in production!
DATA : ls_interval TYPE nriv.
ls_interval-nrrangenr = '01' .
ls_interval-fromnumber = '0000000001' .
ls_interval-tonumber = '9999999999' .
ls_interval-nrlevel = '0000000000' . " Reset
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_UPDATE'
Class CL_NUMBERRANGE_RUNTIME
DATA : lo_nr TYPE REF TO cl_numberrange_runtime,
lv_number TYPE cl_numberrange_runtime=>nr_number.
lo_nr = cl_numberrange_runtime=>get_instance(
lv_number = lo_nr->get_next(
WRITE : / 'Number:' , lv_number.
CATCH cx_nr_object_not_found.
MESSAGE 'Number range object not found' TYPE 'E' .
MESSAGE 'Subobject error' TYPE 'E' .
MESSAGE 'Interval error' TYPE 'E' .
Number Range in Update Task
" Reserve number only on COMMIT
CALL FUNCTION 'NUMBER_GET_NEXT'
" Save document with number
ls_order-order_id = lv_number.
INSERT zorders FROM ls_order.
" On ROLLBACK, number is not consumed
" (with buffered assignment)
Create Own Number Range Object (SNRO)
" Create programmatically (rarely needed)
DATA : ls_attributes TYPE nrobj.
ls_attributes-object = 'ZORDER' .
ls_attributes-domlen = 'CHAR10' .
ls_attributes-percentage = 10 . " Warning at 10% remaining
ls_attributes-devclass = 'ZDEV' .
CALL FUNCTION 'NUMBER_RANGE_OBJECT_UPDATE'
attributes = ls_attributes
Create Interval Programmatically
DATA : ls_interval TYPE nriv.
ls_interval-nrrangenr = '01' .
ls_interval-fromnumber = '0000000001' .
ls_interval-tonumber = '9999999999' .
ls_interval-externind = ' ' . " Internal
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_CREATE'
Number Range Transport
" Number range objects are transported
" Intervals must be maintained separately!
" In target system, create intervals:
" Transaction SNUM -> Maintain intervals
REPORT znr_interval_setup.
CALL FUNCTION 'NUMBER_RANGE_INTERVAL_CREATE'
fromnumber = '0000000001'
tonumber = '9999999999' )
interval_already_exist = 1
" Interval already exists
Number Range Types
Type Flag Description Internal externind = ’ ‘ System assigns number External externind = ‘X’ User provides number Buffered buffer > 0 Numbers are preloaded Rollback-capable Not consumed on error
Interval Strategy
Scenario Recommendation Year-dependent Interval per year (01-2024, 01-2025) Client-specific Subobject = Client Plant-related Subobject = Plant High throughput Activate buffering
Best Practices
Gap-free assignment : Only when really required
Buffering : Activate for mass processes
Monitoring : Check utilization regularly
Test data : Use separate intervals for tests
Rollback : Don’t waste numbers on errors
Year change : Create new intervals in time
Related Articles ABAP Unit Testing: Test-Driven Development Learn to write ABAP Unit Tests: CL_ABAP_UNIT_ASSERT, test classes, Setup/Teardown, Test Doubles, and best practices for high-quality code.
Feb 15, 2026 • ABAP-Statements
ABAP Authorization Checks: AUTHORITY-CHECK Learn authorization checks in ABAP: AUTHORITY-CHECK, authorization objects, roles, and profiles. Develop secure applications.
Feb 15, 2026 • ABAP-Statements
ABAP CDS Annotations: Metadata for Fiori and RAP Learn CDS Annotations in ABAP: UI annotations, OData, Semantics, Search, Analytics, and Metadata Extensions with practical examples.
Feb 15, 2026 • ABAP-Statements