Strategy for multiple subdomains --> scoped queries?

A “single tenant” pattern is best for my app: publishing laws for different states and countries. Most of the time, the queries will be scoped by region, but sometimes not.

I’ll have subdomains like:



By default, an Oregon user should see only Oregon results. But some lawyers need to search across many jurisdictions.

(I have an idea how I’d implement this in Rails: A function that returns the current subdomain, and a scope that’d restrict results.)

What would a Phoenix pattern for this look like? What pieces would I need? Would the sharding support be helpful? Umbrella? Or are those too heavyweight? (E.g. I believe I’ll have all “laws” in one table.)


1 Like

I think that you may be reaching for an overly complex solution. From your problem description I believe that this can be handled with a handful of normal modules and functions.

I believe that given a %Plug.Conn{} you can retrieve the subdomain. So the first function current_juristiction/1 would take a %Plug.Conn{} returns the juristiction (e.g. 'oregon' or 'washington').

Then in your Law (or similar) Context you’d have two functions Law.search_laws/1 and Law.search_laws/2. Law.search_laws/1 would take the query and search all juristictions while Law.search_laws/2 would take the query and the juristiction and search in only that juristiction. The controller would receive a parameter that would tell it to search either only the current juristiction or all juristictions.


I would first use a custom Plug to capture the subdomain. To do this you can add the following file:

defmodule AppName.Plugs.Subdomain do
  import Plug.Conn

  @doc false
  def init(default), do: default

  @doc false
  def call(conn, _) do
    case get_subdomain( do
      subdomain when byte_size(subdomain) > 0 ->
        |> assign(:subdomain, subdomain)
      _ -> conn

  defp get_subdomain(host) do
    root_host = AppNameWeb.Endpoint.config(:url)[:host]
    String.replace(host, ~r/.?#{root_host}/, "")

Then you can include include plug AppName.Plugs.Subdomain in your router browser pipeline. You’ll then be able to access the current subdomain via conn.assigns[:subdomain] on every request.

From there you can use the different function like @axelson mentioned as needed and put in place the proper authorizations.

Or, you could have two functions with Law.search_laws/2.

def Law.search_laws("all", query) do
# query all laws
def Law.search_laws(jurisdiction, query) do
# query scoped laws for jurisdiction

Thank you, both of you - these are great suggestions for me to follow up on.

1 Like