M-codeProgram ControlMill · Lathe · 3D printer
M02 & M30: Ending a Program Cleanly
M30 ends the program and sends the cursor back to the first block, ready for the next part. M02 ends it and leaves the cursor sitting on the M02 line. That is the whole difference between the two, and it is why almost every program written for a production machine finishes with M30. Neither code moves anything: both shut off the spindle, the feed and the coolant, and what else they put back to its default is a setting on the control rather than a word in the file.
Syntax
M02 Program end, cursor stays on the M02 block
M30 Program end and rewind to the first blockParameters
| Address | Meaning | Notes |
|---|---|---|
| none | Neither code takes an address on a machine tool control | Each goes in a block of its own, as the last block of the main program. A block number is the only other word that belongs there |
filename | Marlin is the exception | M30 /holes.gco deletes that file from the SD card. The word is not a program end on Marlin at all |
Which modal codes survive the end of a program is the part worth knowing. The spindle, the feed and the coolant stop on both codes. Whether G90, G17 and the live work offset go back to their power-on defaults, or stay exactly as the program left them, is a control setting, and the two most common controls ship it set differently. Write the start block out in full and the question stops mattering.
Example
O0014 (COVER PLATE, FOUR 6.8MM CLEARANCE HOLES)
G21 G17 G40 G49 G80 G90 (safe start block)
T02 M06 (6.8mm stub drill, 2 x D flute length)
G54 (part zero at the bottom left corner)
S3200 M03 (68m/min in 6082, clockwise)
G00 X15. Y15. (first hole, still high)
G43 H02 Z25. M08 (tool 2 length, flood on)
G99 G81 Z-14. R2. F320 (through 12mm of plate, retract to R)
X85. (second hole)
Y55. (third)
X15. (fourth)
G80 M09 (cycle off, coolant off)
G00 Z25. (drill clear of the plate before anything else)
M05 (spindle stopped)
G49 (drop the drill's length offset)
G91 G28 Z0. (Z to machine home)
G28 X0. Y0. (table out, still incremental)
G90 (absolute again for the next part)
M30 (end, rewind, part counters bump)Controller differences
| Control | Behaviour |
|---|---|
| Fanuc | Both codes are auxiliary functions, so the rewind is the builder's ladder tying the decoded M30 to the reset and rewind signal rather than something the control does on its own. What the end of the program does to the modal codes is bit 6 (CLR) of parameter 3402: the cleared state puts the marked G codes back to their power-on values, the reset state leaves them where the program left them, and G20 and G21 are untouched either way. Parameter 6711 holds the parts count and 6712 the total, bumped by M02, M30 or whichever code is written into parameter 6710, and bit 0 of parameter 6700 decides whether M02 and M30 count at all. |
| Haas | Setting 56, "M30 Restore Default G", is the switch that returns modal G codes to defaults at the end of the program, G54 and G80 among them. M30 cancels the tool length offset whichever way the setting is set. The M30 entry names three more settings that change what the code does, so the ending behaviour of two Haas machines on the same shop floor differs by their settings pages. Setting 118, "M99 Bumps M30 Counters", adds an M99 in a main program to the two M30 counters under CURRENT COMMANDS, and only in a main program. |
| Siemens 840D | Three end words rather than two. M2 ends the main program and returns to the beginning of it, M30 does the same thing as M2, so the M02 against M30 distinction a Fanuc programmer works around does not exist here. M17 ends a subroutine, with RET as the alternative that a subroutine uses instead. All of them are predefined by the NCK, so they mean the same thing on every 840D. |
| Mazak | A Mazatrol conversational program is closed by its END unit rather than by an M code, and the END unit carries the return position and the number of repeats as fields. EIA/ISO programs take M02 and M30 as on Fanuc. |
| Grbl | Nothing to rewind: there is no program in the controller, the sender streams the file a line at a time. M2 and M30 are both supported, both return [MSG:Pgm End], and both restore the parser's modes to their defaults, the plane, the distance mode and the work offset among them. A sender that keeps streaming past that line is in G17, G90 and G54 whatever the program had set. |
| Marlin | M30 is not a program end. It is "Delete SD file", it takes a filename, and it needs SDSUPPORT built in. M2 is not a Marlin command at all, so a job finishes when the file finishes rather than on an M code. |
What goes wrong
The drill is still in the hole when the program ends. M30 stops the spindle and rewinds, it does not move the machine, so a program whose last cutting block left a 6.8mm drill 14mm down in the plate leaves it exactly there. Next cycle start runs the safe start block and the first G00 drags that drill sideways through the job. Retract to a clear Z, then home, then end.
Second is M02 on a machine running the same part all day. The cursor stops on the M02 line, so cycle start does nothing until somebody hits reset or searches back to the top, and a shift of that reads as a machine stalling between parts.
Third is modal state outliving the program. Whether G90, G17 and the active work offset go back to defaults at the end is bit 6 (CLR) of parameter 3402 on a Fanuc and Setting 56 on a Haas, and two machines on one floor ship with them set opposite ways. A program leaning on G54 being left over from the last job cuts the next part somewhere else entirely.
Fourth, a program that loops on M99 rather than ending never counts a part. Parameters 6711 and 6712 move on M02, M30 or the code named in parameter 6710, so the counter still reads zero at the end of a 400 off run and the cell's paperwork is guesswork.
Last, Marlin reads M30 as a delete. Post a mill program to a Marlin router and the M30 at the bottom takes the filename after it, not the program.
Updated 11 Oct 2026