tomkonidas

tomkonidas

While reading Programming Phoenix LiveView, I came across a section (Model Change with Schemaless Changesets - Chapter 5) which goes through setting up schemaless changesets for forms that you do not have a database table for.

I am very familiar with this method (I do it all the time), however instead of creating a Schemaless Changeset, I usually opt to just make an Embedded Schema. To me it seems simpler/cleaner to be able to define the struct and the type at the same time instead of maintaining two things (defstruct and types).


Schemaless

defmodule MyApp.Accounts.User do
  defstruct [:first_name, :email]
  @types %{first_name: :string, email: :string}
end

Embedded

defmodule MyApp.Accounts.User do
  @primary_key false  
  embedded_schema do
    field :first_name, :string
    field :email, :string
  end
end

Question:

Are there any reasons to choose schemaless changesets over embedded schemas?

Showing Posts 1 to 8

LostKobrakai

LostKobrakai

Schemaless changesets can be defined at runtime/by code. So it‘s useful when you don‘t have a fixed schema.

cjbottaro

cjbottaro

I’ve always used “embedded” schemas. I don’t think I’ve ever seen the official docs endorse “schemaless”, where as they do the former.

Schemaless feels like it’s dipping into some private API’s with that @types module var… :stuck_out_tongue:

LostKobrakai

LostKobrakai

There‘s no need for it to be a module attribute though. The data can come from wherever:

{%{field: nil}, %{field: :integer}}
|> Ecto.Changeset.cast(params, [:field])
…
linusdm

linusdm

I also found the distinction between using a schemaless changeset and an embedded schema confusing at times.

Part of that confusion stems from the name of “embedded schema”, I think. Using them stand-alone does not require them to be embedded in any way. But I see where the name comes from (using them in combination with a database).

tfwright

tfwright

You can use schemaless changesets without a struct. İ do that when I want to implement lightweight validation for user input that doesn’t pertain directly to an existing schema.

kingdomcoder

kingdomcoder

Schemaless changeset does not support inputs_for (GitHub Issue).

Please, use embedded schemas. This cost me 3 weeks of work.

voughtdq

voughtdq

For Phoenix Forms, no. I always opt for the embedded schema. I have experimented with a kind of Django-like form module where I define, for example, WebWeb.Forms.OnboardingForm and use an embedded schema. Then the save function can run a Multi or just regular stuff from the application modules inside a transaction. It’s kind of nice, but I haven’t decided if it’s the best solution. The idea is that the form is really a web-side concept that just needs to call a few backend functions.

For me, schemaless changesets work well for bulk imports where you want to run data validation and massaging before an insert_all/3. This is mostly for internal use, but I can imagine using it for an API and telling the user which record failed to validate for a better user experience.

Here’s an example, right inside my schema module:

  def schemaless_changeset(attrs) do
    types = Enum.into(__MODULE__.__schema__(:fields), %{}, fn field ->
      {field, __MODULE__.__schema__(:type, field)}
    end)

    {%{}, types}
    |> cast(attrs, Map.keys(types))
  end

Now of course you can just use the actual schema, but it feels “dirty” because you can’t use insert_all/3 on a schema or changeset. So, rather than having apply_changes/1 (or apply_action/2) turn the changeset into a schema then back into a map or keyword list (and forgetting to remove the additional struct fields in the schema ;), I like this approach. As with anything, your mileage may vary.

redrapids

redrapids

Author of Adopting Elixir

We should probably move Programming Phoenix LiveView to embedded, and talk about the tradeoffs.

— All posts loaded —

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New
dillonoconnor
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews