If `main.kcl` waits until the very end to call `makeBolt`, *none* of that work was parallelised – you’ve pushed the cost back onto the serial tail of your script.
**Better:** call it early or move the invocation into another module.
```norun
// bolt_instance.kcl
import makeBolt from "util.kcl"
bolt = makeBolt(5) // executed in parallel
bolt
```
Now `main.kcl` can `import "bolt_instance.kcl" as bolt` and get the result that was rendered while it was busy doing other things.
---
## Whole module import
You can also import the whole module. This is useful if you want to use the
result of a module as a variable, like a part.
```norun
import "tests/inputs/cube.kcl" as cube
cube
|> translate(x=10)
```
This imports the whole module and makes it available as `cube`. You can then
use it like any other object. The `cube` variable is now a reference to the
result of the module. This means that if you change the module, the `cube`
variable will change as well.
In `cube.kcl`, you cannot have multiple objects. It has to be a single part. If
you have multiple objects, you will get an error. This is because the module is
expected to return a single object that can be used as a variable.
The last expression or variable definition becomes the module's return value.
The module is expected to return a single object that can be used as a variable
by whatever imports it.
So for example, this is allowed:
```norun
... a bunch of code to create cube and cube2 ...
myUnion = union([cube, cube2])
```
You can also do this:
```norun
... a bunch of code to create cube and cube2 ...
union([cube, cube2])
```
Either way, the last line will return the union of the two objects.
Or what you could do instead is:
```norun
... a bunch of code to create cube and cube2 ...
myUnion = union([cube, cube2])
myUnion
```
This will assign the union of the two objects to a variable, and then return it
on the last statement. It's simply another way of doing the same thing.
The final statement is what's important because it's the return value of the
entire module. The module is expected to return a single object that can be used
as a variable by the file that imports it.
---
## Multiple instances of the same import
Whether you are importing a file from another CAD system or a KCL file, that
file represents object(s) in memory. If you import the same file multiple times,
it will only be rendered once.
If you want to have multiple instances of the same object, you can use the
[`clone`](/docs/kcl/clone) function. This will render a new instance of the object in memory.
```norun
import cube from "tests/inputs/cube.kcl"
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```
In the sample above, the `cube` object is imported from a KCL file. The first
instance is translated 10 units in the x direction. The second instance is
cloned and translated 20 units in the x direction. The two instances are now
separate objects in memory, and can be manipulated independently.
Here is an example with a file from another CAD system:
```kcl
import "tests/inputs/cube.step" as cube
cube
|> translate(x=10)
clone(cube)
|> translate(x=20)
```
---
## Importing files from other CAD systems
`import` can also be used to import files from other CAD systems. The format of the statement is the
same as for KCL files. You can only import the whole file, not items from it. E.g.,
```norun
import "tests/inputs/cube.obj"
// Use `cube` just like a KCL object.
```
```kcl
import "tests/inputs/cube.sldprt" as cube
// Use `cube` just like a KCL object.
```
For formats lacking unit data (such as STL, OBJ, or PLY files), the default
unit of measurement is millimeters. Alternatively you may specify the unit
by using an attribute. Likewise, you can also specify a coordinate system. E.g.,
```kcl
@(lengthUnit = ft, coords = opengl)
import "tests/inputs/cube.obj"
```
When importing a GLTF file, the bin file will be imported as well.
Import paths are relative to the current project directory. Imports currently only work when
using the native Design Studio, not in the browser.
### Supported values
File formats: `fbx`, `gltf`/`glb`, `obj`+, `ply`+, `sldprt`, `step`/`stp`, `stl`+. (Those marked with a
'+' support customising the length unit and coordinate system).
Length units: `mm` (the default), `cm`, `m`, `inch`, `ft`, `yd`.
Coordinate systems:
-`zoo` (the default), forward: -Y, up: +Z, handedness: right
-`opengl`, forward: +Z, up: +Y, handedness: right
-`vulkan`, forward: +Z, up: -Y, handedness: left
---
## Performance deep‑dive for foreign‑file imports
Parallelized foreign‑file imports now let you overlap file reads, initialization,
and rendering. To maximize throughput, you need to understand the three distinct
stages—reading, initializing (background render start), and invocation (blocking)
—and structure your code to defer blocking operations until the end.
### Foreign import execution stages
1.**Import (Read / Initialization) Stage**
```kcl
import "tests/inputs/cube.step" as cube
```
- Reads the file from disk and makes its API available.
- Starts engine rendering but **does not block** your script.
- This kick‑starts the render pipeline while you keep executing other code.
2.**Invocation (Blocking) Stage**
```kcl
import "tests/inputs/cube.step" as cube
cube
|> translate(z=10) // ← blocks here only
```
- Any method call (e.g., `translate`, `scale`, `rotate`) waits for the background render to finish before applying transformations.
// --- perform other operations and calculations here ---
cube
|> translate(z=10) // 2) Blocks only here
```
#### 2. Split heavy work into separate modules
Place computationally expensive or IO‑heavy work into its own module so it can render in parallel while `main.kcl` continues.
#### Future improvements
Upcoming releases will auto‑analyse dependencies and only block when truly necessary. Until then, explicit deferral will give you the best performance.