# How to structure a julia package which should also contain a REST api?

**URL:** https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840
**Category:** General Usage
**Tags:** question, webapps, oxygenjl
**Created:** [January 2, 2026, 10:21am UTC](https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840 "2026-01-02T10:21:45Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![DoktorMike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doktormike/32/2736_2.png) [@DoktorMike](https://discourse.julialang.org/u/DoktorMike)
#### Post date: [January 2, 2026, 10:21am UTC](https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840/1 "2026-01-02T10:21:45Z")

</div>

So what I want to do: I want to build a julia package `Foo.jl` which should be used by users writing scripts in julia primarily. There’s also a secondary group of users who will want to use a subset of the package through a REST API.

The most simple structure I can think of is this:

```bash
.
├── Manifest-v1.12.toml
├── Project.toml
├── server.jl
└── src
    └── Foo.jl

```

which I don’t really like since

1. It limits the server code to a single file
2. It issues `using Foo` but foo is just a package that’s not registered. It lives only in the same directory as `server.jl`.

I don’t want to split this up into several repos though. I want a monorepo design.

I could do

```bash
.
├── api
│ └── server.jl
├── Manifest-v1.12.toml
├── Project.toml
└── src
    └── Foo.jl

```

which solves 1. but not 2.

Has anyone a good feel for what the best practice here is?

The server.jl code is something like this:

```julia
using Oxygen
using HTTP
using Foo # The package

@get "/greet" function (req::HTTP.Request)
    return "hello world!"
end

# start the web server
serve()

```

which uses Oxygen.jl but this question is not limited to Oxygen.jl of course.

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [January 2, 2026, 11:39am UTC](https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840/2 "2026-01-02T11:39:50Z")

</div>

> [@DoktorMike](#):
>
> 1. It issues `using Foo` but foo is just a package that’s not registered. It lives only in the same directory as `server.jl`.

This sounds mostly like a question of perspective. From my point of view it’s `server.jl` that happens to live within the `Foo` package and thus there’s nothing strange about `using Foo`. But then I would also start `server.jl` with

```julia-auto
using Pkg
Pkg.activate(@ __DIR__ )
Pkg.instantiate()

```

On the other hand you’re using Julia 1.12, so the best practice would probably be to use the Pkg workspace feature to set up the `api` environment and package the REST api as a Pkg App.

---

<div class="post-metadata">

### Author: ![DoktorMike](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/doktormike/32/2736_2.png) [@DoktorMike](https://discourse.julialang.org/u/DoktorMike)
#### Post date: [January 2, 2026, 12:13pm UTC](https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840/3 "2026-01-02T12:13:41Z")

</div>

That makes sense. I think I will use this approach first then. I’m not familiar with the App concept in Pkg yet.

---

<div class="post-metadata">

### Author: ![ndortega](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ndortega/32/37018_2.png) [@ndortega](https://discourse.julialang.org/u/ndortega)
#### Post date: [January 2, 2026, 6:14pm UTC](https://discourse.julialang.org/t/how-to-structure-a-julia-package-which-should-also-contain-a-rest-api/134840/4 "2026-01-02T18:14:35Z")

</div>

Hi @DoktorMike,

I’d also heavily recommend using the `@oxidise` macro in your package.

If your consumers also have Oxygen.jl installed in the same project they’ll end up using the same internal state object - which will cause all routes to get registerd to the same instance.

This macro will create a new internal context object in the current module _(and bind all stateful methods to it)_ instead of leveraging the global one and prevent any accidental collisions or overwrites.

```julia
module MyServer

using HTTP
using Oxygen; @oxidize 
# now all the @get, @put, serve()... methods are bound to this module

export start, stop

# if we want to register routes outside of this module and have them bound to the same internal state, you'll need to add the exports to this module like this:
export @get, @post

@get "/" function()
    return text("hello world")
end 

start() = serve()
stop() = terminate()

end

```

Now somewhere else you can import your sever module and work with it

```julia
module Main

# only pull in the text helper method since @get is coming from the custom module
using Oxygen: text

# now we have access to the exported methods of the server
include("./MyServer.jl"); using .MyServer

# And we can register new routes on the same server instance outside of the file
@get "/custom" function()
     return text("a custom endpoint")
end

start()

end

```
