Modular Dialplan Organization
Modular Dialplan Organization
As a dialplan grows beyond a few dozen extensions, maintaining everything in a single extensions.conf becomes unmanageable. The #include directive lets you split the dialplan across multiple focused files.
File Structure
/etc/asterisk/
extensions.conf <- Master file, includes everything
extensions_main.conf <- Include hub
extensions_phones.conf <- User group contexts
extensions_services.conf <- Utility/service extensions
extensions_cos.conf <- Class of Service route contexts
Master File (extensions.conf)
[general]
static = yes
writeprotect = no
clearglobalvars = yes
[globals]
TRUNK = PJSIP/trunk-endpoint
RINGTIME = 20
#include extensions_main.conf
Include Hub (extensions_main.conf)
; This file included by extensions.conf
; It includes all the sub-files in the right order
#include extensions_phones.conf
#include extensions_services.conf
#include extensions_cos.conf
Service Extensions (extensions_services.conf)
[services]
; Speaking clock
exten => *86,1,Answer()
same => n,Playback(silence/1)
same => n,SayUnixTime()
same => n,Hangup()
; Echo test
exten => *87,1,Answer()
same => n,Echo()
same => n,Hangup()
; Record and playback test
exten => *88,1,Answer()
same => n,Playback(silence/1)
same => n,Playback(beep)
same => n,Record(test_${CALLERID(num)}:wav)
same => n,Wait(1)
same => n,Playback(test_${CALLERID(num)})
same => n,Hangup()
Phone Contexts (extensions_phones.conf)
[office]
include => services
include => internal
include => pstn-local
include => pstn-long-distance
include => catchall
[lobby]
include => services
include => internal
include => catchall
Route Contexts (extensions_cos.conf)
[internal]
exten => _1XXX,1,Dial(PJSIP/${EXTEN},${RINGTIME})
[pstn-local]
exten => _9NXXXXXX,1,Dial(${TRUNK}/${EXTEN:1})
[pstn-long-distance]
exten => _91NXXNXXXXXX,1,Dial(${TRUNK}/${EXTEN:1})
[catchall]
exten => _X.,1,Playback(an-error-has-occurred)
same => n,Congestion()
How it works
#include filename: A preprocessor directive that inserts the contents of the named file at that point. It runs at parse time, so the result is as if everything were in one file. Paths are relative to/etc/asterisk/.- Include order matters: Files are parsed top-to-bottom. If a context is referenced by
include =>before the file defining it is#include'd, the dialplan will still work becauseinclude =>is resolved at runtime, not parse time. However, keeping#includeorder logical aids readability. #includevsinclude =>: These are completely different.#includeis a file-level preprocessor directive that pulls in another config file.include =>is a dialplan directive that makes one context search another context for extension matches.[globals]section: Define shared variables (trunk name, ring timeout, etc.) once inextensions.conf. All contexts across all included files can reference${TRUNK}and${RINGTIME}.static = yes: Prevents the dialplan from being modified at runtime via AMI or pbx_config. This is the safest setting for file-based dialplans.
Tips
- Reload after changes:
asterisk -rx "dialplan reload". This reloads all#include'd files. - Verify with
dialplan showto see the fully assembled dialplan. Usedialplan show officeto view a specific context. - Keep one context per responsibility. Don't mix internal extension definitions with outbound routing in the same file.
- Use comments at the top of each file documenting what includes it and what it contains.
- For very large deployments, consider
pbx_luaorpbx_aelas alternatives to the INI-style dialplan format. - Back up all
extensions_*.conffiles together: they form a dependency chain.
User Notes
No notes yet. Be the first to contribute a tip or example.
Contribute a note
Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.