# Single vs. Multiple Mutations for Serial Workflow

**URL:** <https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504>\
**Category:** Schema Design\
**Tags:** schema-design\
**Created:** [October 15, 2025, 4:42pm UTC](https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504 "2025-10-15T16:42:53Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![tylergoelz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/tylergoelz/32/5516_2.png) [@tylergoelz](https://community.apollographql.com/u/tylergoelz)\
**Post date:** [October 15, 2025, 4:42pm UTC](https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504/1 "2025-10-15T16:42:53Z")

</div>

My team has an end-user requirement to “activate a feature” and then “save a profile” through a single user action (form submission).

As we begin the schema design process, my initial thought was to create a single `activateAndSaveProfile` mutation within the feature set’s namespace. This would abstract the transactional (and serial) workflow into one GraphQL operation. However, I’m now considering whether it might be better to expose two separate mutations - `activate` and `saveProfile` -within the same namespace, allowing them to be called serially but independently (read more about [namespaces for serial mutations](https://www.apollographql.com/docs/graphos/schema-design/guides/namespacing-by-separation-of-concerns#namespaces-for-serial-mutations)).

Example: Single Mutation (nested in namespace)

```graphql
mutation ActivateAndSaveAccount(...) {
  namespace {
    activateAndSaveProfile(...) {
      ...
    }
  }
}

```

Example: Multiple Serial Mutations (nested in namespace)

```graphql
mutation ActivateAndSaveAccount(...) {
  namespace {
    activate(...) {
      ...
    }
    saveProfile(...) {
      ...
    }
  }
}

```

A few considerations:

- The “saveProfile” operation doesn’t appear to depend on any data returned from “activate”. If it does, we can always call the same API that checks activation status before saving the profile within the save profile resolver.
- There’s a future requirement to allow profile updates, which means a “saveProfile”-type mutation will need to be exposed anyway.
- We’re still working out the input/output structure for this functionality. So the absence of that detail here isn’t for simplicity - it’s genuinely still an “unknown.”
- The Graph I’m working on was originally built as a thin API wrapper during the POC/MVP period - mostly direct mappings of underlying APIs to queries and mutations. I’m now migrating toward a Demand-Oriented Schema Design. That’s why I initially leaned toward a single mutation (it simplifies the consumer experience by abstracting the workflow into one call) rather than requiring consumers to understand and orchestrate multiple nested mutations in a specific order.

Has anyone faced a similar scenario? Which approach did you choose - single mutation or multiple? How did it play out? Were you happy with the decision, or do you wish you’d gone a different route?

---

<div class="post-metadata">

**Author:** ![tylergoelz](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/tylergoelz/32/5516_2.png) [@tylergoelz](https://community.apollographql.com/u/tylergoelz)\
**Post date:** [October 16, 2025, 8:53pm UTC](https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504/2 "2025-10-16T20:53:14Z")

</div>

As a follow-up, our team decided to move forward with the composite mutation, calling it `activateHomeProfile` (as opposed to something with ‘and’ in it) and build the underlying resolver / service / datasource logic to be easily re-used when/if we expose individual mutations for each portion of the transaction (for example, later when we need to ‘update home profile’ or if we ever need a stand alone ‘activation’ step).

---

<div class="post-metadata">

**Author:** ![michaeldouglasdev](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/michaeldouglasdev/32/4911_2.png) [@michaeldouglasdev](https://community.apollographql.com/u/michaeldouglasdev)\
**Post date:** [October 18, 2025, 8:58pm UTC](https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504/3 "2025-10-18T20:58:03Z")

</div>

Hello Tyler!

Good to talk to you again.

A while ago, I was thinking exactly the same way about grouping mutations to reduce the number of requests.

For example, imagine having both `createUser` and `login` mutation fields.  
Obviously, `createUser` could return a JWT token, but that would give it an extra responsibility, and conceptually, creating a user should only handle user creation, not authentication.

As you mentioned, mutations are executed sequentially when defined at the root level.  
However, when fields are nested, they are executed in parallel.

In my case, I also had a namespace-based structure, and to deal with sequential vs. parallel execution, I had to use aliases for the namespaces.

One interesting behavior I noticed was this:  
when the user creation succeeds, the login works fine.  
When the `createUser` field throws an error using `throw new GraphQLError`, the `login` field is not called, which is the expected behavior.  
However, when using a type-based error handling approach, the `login` field is always executed, since the previous field (`createUser`) didn’t actually throw, even though it failed logically.  
This happens both when using a `success: Boolean!` flag or when modeling responses with a union type.

I had tried to create a directive called `@dependsOn(requires: "")` to reduce the number of requests, but no success.  
Check out my idea:

```auto
mutation CreateAndLoginMutation(
  $loginInput: LoginInput!
  $createUserInput: CreateUserInput!
) {
  accountsCreate: accounts {
    createUser(input: $createUserInput) {
      __typename
      ... on User {
        id
        name
        email
      }
      ... on EmailIsAlreadyTakenError {
        message
        code
      }
      ... on GenericError {
        message
        code
      }
    }
  }

  accountsLogin: accounts {
    login(input: $loginInput) @dependsOn(requires: "accountsCreate.createUser.__typename === 'User'") {
      __typename
      ... on Auth {
        token
        user {
          id
          name
          email
        }
      }
      ... on InvalidCredentialsError {
        message
      }
      ... on GenericError {
        message
      }
    }
  }
}

```

I think I’ll try again, but using Apollo Plugins, @graphql-tools/utils (mapSchema) and metadata, just like I did in the previous topic

> [@Input argument validation](https://community.apollographql.com/t/input-argument-validation/8672/22):
>
> I’m back with updates! My previous implementation wasn’t working quite as expected, especially with nested fields. In those cases, the parent resolver was executed before input validation occurred in the nested fields, which wasn’t ideal for me. I want to validate all inputs first, regardless of whether they’re placed in nested fields or at the root, and only then execute the resolvers. After experimenting, I found a better approach: I’m still using mapSchema to attach metadata, and I moved t…

---

<div class="post-metadata">

**Author:** ![michaeldouglasdev](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/michaeldouglasdev/32/4911_2.png) [@michaeldouglasdev](https://community.apollographql.com/u/michaeldouglasdev)\
**Post date:** [October 20, 2025, 7:05pm UTC](https://community.apollographql.com/t/single-vs-multiple-mutations-for-serial-workflow/9504/4 "2025-10-20T19:05:53Z")

</div>

I’ve uploaded my custom GraphQL directives (@dependsOn and @range) to GitHub: [GitHub - michaeldouglasdev/graphql-directives](https://github.com/michaeldouglasdev/graphql-directives)

They’re working great for most cases, but I’m running into an issue with namespace scenarios where fields depend on nested fields. Ex: `accounts { create {...}}`

I was digging through the GraphQL-JS code and found `executeFieldsSerially` ([graphql-js/src/execution/execute.ts at 16.x.x · graphql/graphql-js · GitHub](https://github.com/graphql/graphql-js/blob/16.x.x/src/execution/execute.ts#L406)). The field results get added to the `results` reduce function variable, but `results` is never passed to `executeField` and consequently not available in `buildResolveInfo`.

I’m wondering if we could add the `results` to the `rootValue` field in the `info` object. This would make previously executed field results available to subsequent field resolvers, which it inclusive would help a lot with my @dependsOn directive hahaha

Does anyone know if there would be any issues with adding mutation results to rootValue? Or if there’s a better approach for making mutation root field results available to other resolvers?

Maybe I can do a PR.  
I’m going to test.

Thanks! 🚀
