CNC milling programming drives a 3-axis (or more) machine where the spindle holds the tool and the table holds the work. You move the tool through a sequence of straight lines, arcs and pre-built cycles to remove material.
This guide uses Fanuc-style syntax (Haas, Mazak Mill, and most controls share 95% of these codes).
1. The Milling Coordinate System
A vertical milling machine uses three linear axes — X (table left/right), Y (table in/out), Z (spindle up/down).
Right-Hand Rule
Point your right hand so the thumb = +X, index = +Y, middle = +Z. That's the machine convention everywhere on the planet.
2. Anatomy of a Milling Block
N40 G01 X25.0 Y10.0 Z-2.0 F250 ;
│ │ │ │ │ │
│ │ │ │ │ └── feed (mm/min with G94)
│ │ │ │ └── target Z (cutting depth)
│ │ │ └── target Y
│ │ └── target X
│ └── motion mode (linear feed)
└── line number
Key letter addresses for milling:
| Letter | Meaning |
|---|---|
| G / M | Preparatory / miscellaneous |
| X, Y, Z | Linear axes |
| A, B, C | Rotary axes about X, Y, Z (4/5-axis) |
| I, J, K | Arc centre offsets from arc start (X, Y, Z) |
| R | Arc radius (alternative to I/J) |
| F | Feed rate (mm/min) |
| S | Spindle RPM |
| T | Tool number |
| D | Cutter radius offset register |
| H | Tool length offset register |
| P | Subprogram call / dwell time |
3. The Essential G-Code Reference (Milling)
Motion (Group 01)
| Code | What it does |
|---|---|
| G00 | Rapid traverse |
| G01 | Linear feed |
| G02 | Circular feed, clockwise (in current plane) |
| G03 | Circular feed, counter-clockwise |
Plane selection (Group 02)
| Code | Plane |
|---|---|
| G17 | XY plane (default — top-down work) |
| G18 | XZ plane (side-on work) |
| G19 | YZ plane |
Plane matters for arcs and cutter compensation — choose G17 for normal flat-table work.
Coordinate / unit modes
| Code | What it does |
|---|---|
| G20 / G21 | Inch / metric |
| G90 / G91 | Absolute / incremental |
| G94 / G95 | Feed per minute / per revolution |
| G54..G59 | Work-coordinate systems 1..6 |
Tool compensation
| Code | What it does |
|---|---|
| G40 | Cancel cutter radius compensation |
| G41 | Cutter comp left of programmed path (climb cut) |
| G42 | Cutter comp right of programmed path (conventional cut) |
| G43 | Tool length comp positive (use H register) |
| G44 | Tool length comp negative (rarely used) |
| G49 | Cancel tool length comp |
Drilling / hole-making canned cycles
| Code | What it does |
|---|---|
| G80 | Cancel canned cycle |
| G81 | Plain drill (rapid-feed-rapid) |
| G82 | Spot drill / counterbore (drill + dwell + retract) |
| G83 | Peck drill (full retract between pecks — chip clearance) |
| G73 | High-speed peck (small retract between pecks — fast) |
| G84 | Right-hand tapping |
| G85 | Bore — feed in, feed out (good finish) |
| G86 | Bore — feed in, spindle stop, rapid out |
| G89 | Bore — feed in, dwell, feed out |
Return mode for cycles
| Code | What it does |
|---|---|
| G98 | Return to initial plane after each hole |
| G99 | Return to R-plane between holes (faster, but watch for clamps) |
M-codes you must know
| Code | Meaning |
|---|---|
| M03 / M04 / M05 | Spindle CW / CCW / stop |
| M06 | Tool change |
| M08 / M09 | Coolant on / off |
| M30 | Program end + rewind |
| M98 P_ | Call subprogram |
| M99 | End subprogram, return to caller |
4. Work Coordinate Systems (G54–G59)
The machine has two coordinate systems: machine zero (set at machine home) and work zero (set on each part by you). G54..G59 are six work-offset registers.
G54 G90 G17 G21 ; "Use work offset 1, absolute, XY plane, metric"
G00 X0 Y0 ; Goes to the X0 Y0 of work-offset 1 (i.e. part zero)
The operator sets G54 by jogging to the corner of the part and pressing "Set Work Offset" — then your program is portable: same G-code, different fixture position.
5. Tool Length & Cutter Radius Compensation
Length compensation (G43 H_)
Each tool has a different length. Instead of recomputing Z for every tool, the operator measures each tool and stores its length in an H-register (H01 for tool 1, H02 for tool 2…). Your program just calls:
T01 M06 ; load tool 1
G43 H01 Z25.0 ; "apply tool 1 length, go to Z25"
Radius compensation (G41/G42 D_)
Same idea for cutter diameter. You program the finished part edge;
the control offsets the toolpath by D (radius register).
G01 G41 D01 X10.0 Y0.0 F300 ; comp LEFT (climb), use D01
Y50.0
X40.0
Y0.0
X-2.0
G40 ; cancel comp before retract
Climb vs conventional:
| Comp side (Y up = +Y) | Effect | |
|---|---|---|
| G41 (left) | Tool sits to left of motion | Climb milling — better finish, lower cutter wear |
| G42 (right) | Tool sits to right of motion | Conventional milling — used on hand-feed mills |
CNC mills almost always climb (G41 around an outside contour going counter-clockwise; G42 going clockwise).
6. Drilling Cycles — In Depth
The format for every drilling cycle is the same:
G## X_ Y_ Z_ R_ Q_ P_ F_ ;
; │ │ │ │ │ │ └── feed (mm/min)
; │ │ │ │ │ └── dwell time (ms, for G82/G89)
; │ │ │ │ └── peck depth (G83/G73 only)
; │ │ │ └── R-plane = where rapid switches to feed
; │ │ └── final hole bottom Z (in absolute or incremental)
; │ └── Y of hole
; └── X of hole
After the first call, every subsequent block of just X Y triggers another
hole at the same depth — modal drilling.
G81 — Plain Drill
G90 G54 G00 X10.0 Y10.0 ; first hole position
G43 H03 Z25.0 ; tool length offset
M03 S1500
G99 G81 R2.0 Z-15.0 F180 ; drill: rapid to R, feed to Z, rapid out
X30.0 ; second hole — same depth
X50.0
X70.0 Y30.0
G80 ; cancel cycle
G00 Z50.0
G83 — Peck Drill (deep holes, full retract)
For holes deeper than ~3 × diameter, peck to clear chips:
G99 G83 R2.0 Z-40.0 Q5.0 F120
; │ │ │
; │ │ └── peck depth = 5 mm each step
; │ └── final depth -40 mm
; └── R-plane (start of feed)
The tool feeds 5 mm, rapids back to R, rapids back to the previous peck depth, feeds another 5 mm, repeats until Z-40.
G73 is the same idea but with a small retract (typically 1 mm) — much
faster, used when chip clearance is less critical (aluminium).
G84 — Tapping
G95 ; feed/rev
G99 G84 R5.0 Z-15.0 F1.5 ; for M8 × 1.25 thread, F = pitch = 1.25
G94 ; back to feed/min
The control synchronises spindle and Z so the tap doesn't tear the thread. Modern machines use rigid tapping — no floating tap holder needed.
7. Arc Programming (G02 / G03)
Two ways to define an arc — R (radius) or I/J (centre offsets):
; Arc from (10, 0) to (10, 20), centre at (10, 10), CCW, radius 10:
G01 X10.0 Y0.0 F250
G03 X10.0 Y20.0 R10.0 ; R-style
; OR
G03 X10.0 Y20.0 I0 J10.0 ; centre offset: 0 in X, +10 in Y from start
Use I/J for full circles — R can't define a 360° arc (ambiguous).
| Direction in XY (G17) | |
|---|---|
| G02 | Clockwise (looking down +Z) |
| G03 | Counter-clockwise |
8. Subprograms (M98 / M99)
Repeated patterns belong in subprograms. Main program calls with M98:
; --- main ---
G54 G90 G00 X0 Y0 Z25.0
M98 P1000 L4 ; call O1000 four times
M30
; --- subprogram O1000 ---
O1000
G91 ; relative
G81 X20.0 R2.0 Z-15.0 F180
G80
M99 ; return
L (or K on some controls) sets repeat count. The subprogram drills four
holes 20 mm apart along X — a hole pattern, defined once.
9. Two Complete Worked Programs
Program 1: 4-hole bolt pattern + counterbore
A 50 × 50 mm plate, four Ø6 mm bolt holes on a 30 × 30 mm pattern, each counterbored Ø10 × 5 mm deep:
%
O1001 (BOLT PATTERN)
(--- Tool 1: Ø6 drill, H01 ---)
T01 M06
G54 G90 G17 G21 G94
G43 H01 Z25.0 M03 S2200
M08
G99 G81 X10.0 Y10.0 R2.0 Z-22.0 F220
X40.0 Y10.0
X40.0 Y40.0
X10.0 Y40.0
G80
G00 Z50.0 M09
M05
(--- Tool 2: Ø10 endmill for counterbore, H02 ---)
T02 M06
G43 H02 Z25.0 M03 S1800
M08
G99 G82 X10.0 Y10.0 R2.0 Z-5.0 P200 F300 ; G82 spot/c-bore with dwell
X40.0 Y10.0
X40.0 Y40.0
X10.0 Y40.0
G80
G00 Z50.0 M09
M05
M30
%
Program 2: Profile a 60 × 40 mm pocket-edge with cutter comp
Mill the OUTSIDE profile of a 60 × 40 mm rectangle (fillets R5) with a Ø10 mm endmill, climb cutting:
%
O1002 (CONTOUR MILL — RECTANGLE 60x40 R5)
T05 M06 ; Ø10 endmill, D05 = 5.0 mm
G54 G90 G17 G21 G94
G43 H05 Z25.0 M03 S2400
M08
G00 X-15.0 Y-10.0 ; start outside the part
Z2.0
G01 Z-5.0 F250 ; plunge to depth
G41 D05 X0.0 Y0.0 F600 ; engage comp going to corner (0, 0)
X55.0 ; bottom edge → corner before fillet
G02 X60.0 Y5.0 R5.0 ; bottom-right fillet
G01 Y35.0
G02 X55.0 Y40.0 R5.0 ; top-right fillet
G01 X5.0
G02 X0.0 Y35.0 R5.0 ; top-left fillet
G01 Y5.0
G02 X5.0 Y0.0 R5.0 ; bottom-left fillet
G01 X-15.0 ; lead-out clear of part
G40 ; cancel comp
G00 Z25.0 M09
M05
M30
%
Two things to notice:
- The lead-in (
G01 X0 Y0) is straight — required for G41/G42 to engage cleanly. - All four corner arcs use
G02because we're going clockwise (so the comp sideG41keeps the cutter on the outside of the part).
10. Quick Cheat Notes
- Right-hand rule — thumb X, index Y, middle Z. Z is ALWAYS up.
- Set G54 first — every modern part program starts on a work offset.
- Always issue
G43 H_after a tool change before plunging in Z. - G41 = climb (left of path), G42 = conventional (right of path).
- G80 cancels canned cycles — forget it and your next G00 will drill a hole.
- For arcs > 180° or full circles use I/J, not R.
- G99 stays at R-plane between cycle holes (fast); G98 returns to initial plane (clears clamps).
- M98 P_ L_ = call subprogram L times — the cleanest way to handle repeating patterns.
- Tap feed rate (with G94) =
pitch × RPM. With G95, justF = pitch. - Test with single-block + 25% rapid override the first run.