Maybe you should take a look what the function createField does
Creates a field with a given config.
return craft\base\FieldInterface The field
It only creates a PHP object but does not save the field at all.
Craft::$app->getFields()->saveField($field);
is what you want
This is what the FieldsController does to store a new field
public function actionSaveField() { $this->requirePostRequest(); $fieldsService = Craft::$app->getFields(); $request = Craft::$app->getRequest(); $type = $request->getRequiredBodyParam('type'); $field = $fieldsService->createField([ 'type' => $type, 'id' => $request->getBodyParam('fieldId'), 'groupId' => $request->getRequiredBodyParam('group'), 'name' => $request->getBodyParam('name'), 'handle' => $request->getBodyParam('handle'), 'instructions' => $request->getBodyParam('instructions'), 'translationMethod' => $request->getBodyParam('translationMethod', Field::TRANSLATION_METHOD_NONE), 'translationKeyFormat' => $request->getBodyParam('translationKeyFormat'), 'settings' => $request->getBodyParam('types.'.$type), ]); if (!$fieldsService->saveField($field)) { Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t save field.')); // Send the field back to the template Craft::$app->getUrlManager()->setRouteParams([ 'field' => $field ]); return null; } Craft::$app->getSession()->setNotice(Craft::t('app', 'Field saved.')); return $this->redirectToPostedUrl($field); }