Most 3D tools ask you to push and pull geometry with a mouse. OpenSCAD does not. You write a script — and the script is the model. No file format that diverges from the source of truth, no “I moved something by hand and now I can’t reproduce it”, no .blend file that is a black box. Just text that describes a solid object, and a renderer that turns it into a mesh.

What is OpenSCAD?

OpenSCAD is a script-only parametric 3D CAD modeller. It functions as a “3D compiler”: you describe your object using geometric primitives and boolean operations, and OpenSCAD evaluates the script to produce an exact solid mesh that you can export for 3D printing, CNC machining, or further CAD work.

“OpenSCAD is a software for creating solid 3D CAD objects. It is free software and available for Linux/UNIX, Windows and Mac OS X. Unlike most free software for creating 3D models, OpenSCAD focuses on the CAD aspects rather than the artistic aspects of 3D modelling.”

OpenSCAD Source Code on GitHub OpenSCAD Website OpenSCAD Documentation

What makes it different from every other 3D tool

  • 📝 Code is the model.scad files are plain text; git diff tells you exactly what changed between versions
  • 🔁 Perfect reproducibility — the same script always produces the exact same geometry
  • 🔩 Parametric by nature — change a variable at the top and the entire model updates
  • 🖥️ Headless CLI — export STL/3MF/SVG from a shell script or CI pipeline with zero GUI
  • 🧮 CSG-based — union, difference, intersection of solids; impossible to produce non-watertight meshes from valid geometry
  • ⚖️ GPL v2 licensed — completely free, forever

How OpenSCAD Works

OpenSCAD evaluates your script in a pipeline:

.scad script
  → Lexer (Flex) + Parser (Bison) → AST
  → Evaluator                     → values and context
  → CSG Tree builder              → geometry nodes
  → CGAL / Manifold               → exact solid mesh
  → Export                        → STL, 3MF, SVG, PNG…

The preview window uses OpenCSG — a fast screen-space renderer that gives you interactive feedback while you type. The export path uses CGAL (the Computational Geometry Algorithms Library) or Manifold for exact boolean operations on solid geometry. Both backends produce correct results; CGAL is more established, Manifold is faster for certain operations.

The OpenSCAD Language

Building shapes

// 3D primitives
cube([40, 20, 10], center=true);
sphere(r=5, $fn=100);           // $fn = facet count → smoothness
cylinder(h=20, r=5, $fn=60);

// 2D primitives (used for extrusions)
square([30, 15], center=true);
circle(r=8, $fn=100);
polygon(points=[[0,0],[20,0],[10,15]]);
text("Hello", size=8, font="Liberation Sans");

Combining shapes with CSG

difference() {
    cube([40, 30, 15], center=true);        // the base
    cylinder(h=20, r=6, center=true);       // the hole
}

union() {
    cube(10);
    translate([8, 0, 0]) sphere(r=6);
}

intersection() {
    sphere(r=10);
    cube(14, center=true);
}

Transformations

translate([10, 0, 0]) cube(5);
rotate([0, 0, 45])    cube(10, center=true);
scale([2, 1, 0.5])    sphere(r=5);
mirror([1, 0, 0])     cylinder(h=10, r=3);

Making it parametric

// Parameters at the top
length   = 80;     // mm
width    = 40;
height   = 10;
hole_r   = 5;
wall     = 3;

// The model references them
difference() {
    cube([length, width, height]);
    translate([length/2, width/2, -1])
        cylinder(h=height+2, r=hole_r, $fn=60);
}

Change hole_r = 8 — the hole updates. Change length = 120 — the whole part scales. This is the parametric promise, delivered in plain text.

Modules — reusable geometry blocks

module rounded_box(dims, r=2, $fn=32) {
    minkowski() {
        cube(dims - [r*2, r*2, r*2], center=true);
        sphere(r);
    }
}

rounded_box([60, 40, 20]);
rounded_box([30, 30, 10], r=4);

Loops, functions, and list comprehensions

// Arrange copies in a grid
for (x = [0:3], y = [0:3])
    translate([x*20, y*20, 0]) sphere(r=4);

// Function
function area(r) = PI * r^2;

// Anonymous function (2021.01+)
let(clamp = function(v, lo, hi) min(max(v, lo), hi))
    echo(clamp(150, 0, 100));

// List comprehension → array of positions
pts = [for (a = [0:36:360]) [cos(a)*20, sin(a)*20]];
polygon(pts);

Extrusions

// Extrude a 2D shape into 3D
linear_extrude(height=15, twist=90, scale=0.5)
    square(10, center=true);

// Rotate a 2D profile around the Z axis
rotate_extrude(angle=270, $fn=120)
    translate([15, 0]) circle(r=5);

The Customizer

OpenSCAD includes a Customizer panel that turns annotated variables into sliders, checkboxes, and text inputs — without touching the code:

/* [Main dimensions] */

// Total length (mm)
length = 80;   // [20:200]

// Wall thickness
wall = 3;      // [1:0.5:8]

// Add mounting holes?
holes = true;  // checkbox

// Label text
label = "v1";  // text field

/* [Hidden] */    // params below this are not shown in Customizer
debug = false;

Presets are saved as JSON files and can be fed back to the CLI for batch export:

openscad -p variants.json -P "Large" -o large.stl bracket.scad
openscad -p variants.json -P "Small" -o small.stl bracket.scad

Installing OpenSCAD

Desktop (interactive use)

Headless server (no display required)

OpenSCAD’s CLI works without a display server. Install the package or AppImage on any Linux server:

# Debian / Ubuntu
sudo apt install openscad

# Verify headless export works
echo "sphere(r=10);" | openscad -o test.stl --stdin

Headless Automation

This is where OpenSCAD shines for self-hosters and DevOps engineers.

Basic export

# STL for 3D printing
openscad -o part.stl design.scad

# 3MF (richer format — colours, metadata)
openscad -o part.3mf design.scad

# PNG preview with custom camera
openscad -o preview.png \
  --camera=0,0,0,45,0,30,250 \
  --imgsize=1920,1080 \
  design.scad

Parametric variants from the command line

# Override any top-level variable
openscad -D 'length=50' -D 'wall=2' -o thin_50.stl bracket.scad
openscad -D 'length=80' -D 'wall=4' -o thick_80.stl bracket.scad

# Export multiple formats in one pass
openscad \
  -D 'size=60' \
  -o part.stl \
  -o part.3mf \
  -o preview.png \
  design.scad

Animation frame rendering

Use the special $t variable (ranges 0–1 over all frames):

// Spinning animation
rotate([0, 0, $t * 360]) cube([40, 10, 10], center=true);
# Render 60 frames → frame_00001.png … frame_00060.png
openscad -o frame_%05d.png --animate=60 spinner.scad

# Distribute across two machines
openscad -o frame_%05d.png --animate=60 --animate-sharding=0/2 spinner.scad
openscad -o frame_%05d.png --animate=60 --animate-sharding=1/2 spinner.scad

Running in Docker

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y openscad && \
    rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["openscad"]
docker build -t openscad-headless .

docker run --rm \
  -v "$PWD":/work \
  openscad-headless \
  -D 'size=40' \
  -o /work/output.stl \
  /work/design.scad

CI/CD integration

Because OpenSCAD returns a non-zero exit code on errors, it integrates cleanly into any pipeline:

# GitHub Actions example
- name: Export STL
  run: openscad -o part.stl -D 'wall=3' bracket.scad

- name: Upload artefact
  uses: actions/upload-artifact@v4
  with:
    name: bracket
    path: part.stl

Every commit that modifies .scad files triggers a fresh export — the STL in your release artefacts is always in sync with the source.

Why Git + OpenSCAD is the right combination

A Blender .blend or FreeCAD .FCStd file is a binary blob. git diff shows you that it changed; it cannot show you what changed.

An OpenSCAD .scad file is plain text. git diff shows you the exact parameter you adjusted, the line you added, the module you renamed. Code review for mechanical design works the same way as code review for software.

- wall = 2;
+ wall = 3;   // increased for print reliability

This is why OpenSCAD has become the standard format on Thingiverse, Printables, and Makerworld for parametric parts — the source file is the deliverable, not a compiled mesh.

File Format Support

Category Input Output
Native .scad .scad
3D mesh STL, OFF, 3MF, AMF, OBJ STL, OFF, 3MF, AMF, OBJ
2D profile DXF, SVG DXF, SVG
Image PNG
Document PDF
Debug CSG, AST

Conclusion

OpenSCAD occupies a unique and irreplaceable position in the FOSS toolchain: it is the only mainstream CAD tool where the model is the code. That single design decision makes it the right choice for makers who value reproducibility, engineers who want version control, and DevOps people who want to generate geometry from a CI pipeline.

It does not replace FreeCAD for complex assemblies, technical drawings, or FEM analysis. It does not replace Blender for organic shapes, rendering, or animation. But for parametric mechanical parts destined for a 3D printer or CNC mill — especially ones that need to be shared, versioned, and customised — it is the best tool in the FOSS ecosystem.

Related tools worth knowing:

  • CadQuery — Python-first CSG using OpenCASCADE; same “code is the model” philosophy but with full Python and a more capable geometry kernel
  • FreeCAD — GUI parametric CAD with Python API; better for complex assemblies, technical drawings, FEM; steeper learning curve
  • ImplicitCAD — Haskell-based CSG with smooth implicit surfaces; OpenSCAD-compatible syntax
  • SolveSpace — sketch-and-constraint parametric CAD; lightweight, precise, good for 2D-driven 3D