> For the complete documentation index, see [llms.txt](https://osl.mistium.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://osl.mistium.com/language-guide/imports-and-projects.md).

# Imports and project structure

Imports are relative to the file that contains them.

## Import forms

| Form                        | Meaning                                             |
| --------------------------- | --------------------------------------------------- |
| `import "std:fs"`           | Package embedded in the compiler                    |
| `import "./helpers.osl"`    | One local source file                               |
| `import "helpers"`          | Every `.osl` file directly inside a local directory |
| `import "owner/repository"` | Git package installed by Opal                       |
| `import "go:net/http"`      | Go package                                          |

Directory imports are sorted by filename and are not recursive. Import each child directory explicitly. The compiler emits runtime initialization only for imported files that contain top-level executable statements. A file containing declarations alone adds no runtime initializer.

## A practical layout

Use one top-level entry file and group the rest by responsibility:

```
src/
  main.osl
  api/
    index.osl
    handlers/
  db/
    users/
      storage.osl
      queries.osl
  helpers/
```

`main.osl` should compose the application. Put feature behavior in imported directories. OriginChats uses this layout at production scale: its entry file imports packages, declares shared types and state, imports feature groups, then starts the HTTP and WebSocket servers.

```osl
// src/main.osl
import "std:serve"
import "api"
import "db"
import "helpers"
```

## Exports

Without an export statement, a local file exposes all declarations. Add exports to define an explicit public API:

```osl
export {createUser, deleteUser}
export {User} from "./models.osl"
export * as validation from "./validation"
```

Consumers can merge exports, select names, or create a namespace:

```osl
import * from "./users.osl"
import {createUser} from "./users.osl"
import * as users from "./users.osl"
```

Sibling files in one directory can share private declarations. A consumer in another directory sees only the explicit exports.

## Module objects

The expression form returns a local module as an object:

```osl
object math = import("./math.osl")
log math.add(2, 3)
```

## Go modules

Native builds look for `go.mod` in the entry file's directory and its parents. The compiler copies the selected module files into its generated workspace. A project without `go.mod` uses a generated module in the OSL cache.

## Go packages

Refer to an imported Go package by its Go package name, which is usually the last path element:

```osl
import "go:net/http"
import "go:image"
import "go:strings"
import "go:path"

log http.MethodGet
image.Point p = image.Pt(1, 2)
p.X = 5

def reader() *strings.Reader (
  return strings.NewReader("abc")
)

def shift(function f, string text) string (
  return strings.Map(f, text)
)

string[] parts = ["b", "c"]
log path.Join("a", ...parts)
```

* Exported constants and variables are read directly, as in `http.MethodGet`.
* A Go import is always reachable by its package name, including packages the runtime also imports internally, such as `io`, `os`, and `errors`.
* Go types work as variable, parameter, and return types, both as values (`image.Point`) and pointers (`*strings.Reader`). Field writes on a value variable update that variable. Numbers convert to the field's numeric type, and an unknown field is a `TypeError`.
* Untyped values, such as `function` parameters and object properties, convert to the Go parameter type when passed to a Go function. Functions adapt their arguments and results, so `def(int r) int -> (...)` satisfies `func(rune) rune`.
* Spreading an array into a Go variadic parameter converts each element to the parameter's element type.
* A Go struct builds from named fields, lowering directly to a Go struct literal. Omitted fields keep their Go zero values. Lowercase names map to the exported field (`x` sets `X`); names that already start uppercase pass through unchanged:

```osl
image.Point p = image.Point(y = 2, x = 1)
```

* A Go import that the program never uses still builds, and the compiler reports an `UnusedImportWarning` (`OSL-UNUSED-IMPORT`) on the import line.

Go struct literals such as `image.Point{X: 1}` are not OSL syntax. Use a constructor function.

## Opal projects

Opal manages Git and Go dependencies, exact lock data, scripts, and package commands. An Opal project uses `opal.json`, `opal.lock`, and an ignored `.opal/` directory. See [Opal projects](/tools-and-reference/opal.md).

Package method discovery follows exported variable aliases to their receiver type. Methods implemented with a Go `error` return, or with an explicit `nil` return, retain that nullability in OSL checks. A valid `== null` check on those results is accepted.

## Package handle types

Use the package name when declaring a handle, for example `*cache.Cache`, `*db.DB`, `*process.Process`, or `*ptr.Pointer`. The same names work in function parameters and return types. Go types for package handles use `OSL<package><Type>` consistently, so `*cache.Cache` resolves to `*OSLcacheCache` without a special compiler alias.

An empty array fallback inherits the left operand's element type:

```osl
string[string[]?] groups = {}
string[] values = groups["missing"] ?? []
```

Built-in types such as `result`, `error`, `unit`, `set`, `map`, `option`, `canvas`, and `xml` use bare language names. They do not have qualified package type names or require imports. For example, use `result<int, error>` for a typed result.

Explicit types on imported global variables are available to top-level statements in importing files, including typed arrays, dictionaries, and package handles. Accessing an imported `*cache.Cache` does not require a type assertion. Module initialization still runs once at the import position.
