diff --git a/src/commands/base.ts b/src/commands/base.ts
index 0faa5907e..16d1da5e0 100644
--- a/src/commands/base.ts
+++ b/src/commands/base.ts
@@ -7,7 +7,7 @@ import jsYaml from 'js-yaml'
 import { RepoConfigFromFile, UserConfigFromFile } from '../types'
 import { ClassConstructor, plainToClass } from 'class-transformer'
 import { validateSync } from 'class-validator'
-import { reportValidationErrors, reportZodValidationErrors } from '../utils/reportValidationErrors'
+import { reportValidationErrors, reportZodValidationErrors, validateParams } from '../utils/reportValidationErrors'
 import { getToken } from '../auth/getToken'
 import { fetchProjects } from '../api/projects'
 import { promptForProject } from '../ui/promptForProject'
@@ -15,7 +15,7 @@ import inquirer from 'inquirer'
 import Writer from '../ui/writer'
 import { errorMap, setDVCReferrer } from '../api/apiClient'
 import { Prompt, handleCustomPrompts } from '../ui/prompts'
-import { filterPrompts, mergeFlagsAndAnswers, validateParams } from '../utils/prompts'
+import { filterPrompts, mergeFlagsAndAnswers } from '../utils/prompts'
 import z, { ZodObject, ZodTypeAny, ZodError } from 'zod'
 
 export default abstract class Base extends Command {
@@ -258,7 +258,7 @@ export default abstract class Base extends Command {
     ): Promise<ResourceType> {
         if (flags.headless) {
             const params = plainToClass(paramClass, flags)
-            validateParams(paramClass, params, { whitelist: true, skipMissingProperties: isUpdate })
+            validateParams(params, { whitelist: true, skipMissingProperties: isUpdate })
             return params
         }
 
@@ -266,7 +266,7 @@ export default abstract class Base extends Command {
         const answers = await this.populateParametersWithInquirer(filteredPrompts)
 
         const params = plainToClass(paramClass, mergeFlagsAndAnswers(flags, answers))
-        validateParams(paramClass, params, { whitelist: true, skipMissingProperties: isUpdate })
+        validateParams(params, { whitelist: true, skipMissingProperties: isUpdate })
         return params
     }
 
diff --git a/src/commands/environments/create.ts b/src/commands/environments/create.ts
index a6766f041..64c1b0bb2 100644
--- a/src/commands/environments/create.ts
+++ b/src/commands/environments/create.ts
@@ -10,7 +10,6 @@ import {
 } from '../../ui/prompts'
 import CreateCommand from '../createCommand'
 import { CreateEnvironmentDto } from '../../api/schemas'
-import { ZodError } from 'zod'
 
 export default class CreateEnvironment extends CreateCommand {
     static hidden = false
diff --git a/src/commands/environments/update.ts b/src/commands/environments/update.ts
index de6e9cbbf..a8183c91f 100644
--- a/src/commands/environments/update.ts
+++ b/src/commands/environments/update.ts
@@ -11,7 +11,6 @@ import {
 import UpdateCommand from '../updateCommand'
 import { Flags } from '@oclif/core'
 import { CreateEnvironmentDto, UpdateEnvironmentDto } from '../../api/schemas'
-import { ZodError } from 'zod'
 
 export default class UpdateEnvironment extends UpdateCommand {
     static hidden = false
diff --git a/src/commands/features/create.ts b/src/commands/features/create.ts
index 2d97fd919..8f182a1a6 100644
--- a/src/commands/features/create.ts
+++ b/src/commands/features/create.ts
@@ -59,7 +59,7 @@ export default class CreateFeature extends CreateCommand {
 
         this.prompts.push((new VariableListOptions([], this.writer)).getVariablesListPrompt())
         this.prompts.push(
-            (new VariationListOptions([], this.writer)).getVariationListPrompt()
+            (new VariationListOptions([], [], this.writer)).getVariationListPrompt()
         )
 
         const project = await fetchProject(this.authToken, this.projectKey)
diff --git a/src/commands/features/update.ts b/src/commands/features/update.ts
index d07f562e9..1528f981e 100644
--- a/src/commands/features/update.ts
+++ b/src/commands/features/update.ts
@@ -67,12 +67,16 @@ export default class UpdateFeature extends UpdateCommand {
         this.writer.statusMessage(JSON.stringify(feature, null, 2))
         this.writer.blankLine()
 
-        this.prompts.push((new VariableListOptions([], this.writer)).getVariablesListPrompt(feature.variables))
-        this.prompts.push((new VariationListOptions([], this.writer))
-            .getVariationListPrompt( // if variables flags were passed in, treat those as the new variables
-                feature.variations,
-                variables ? JSON.parse(variables): feature.variables,
+        this.prompts.push((new VariableListOptions(feature.variables ?? [], this.writer)).getVariablesListPrompt())
+        this.prompts.push(
+            (
+                new VariationListOptions(
+                    feature.variations ?? [],
+                    variables ? JSON.parse(variables): feature.variables,
+                    this.writer
+                )
             )
+                .getVariationListPrompt()
         )
         this.prompts.push(getSdkVisibilityPrompt(feature))
 
diff --git a/src/ui/prompts/commonPrompts.ts b/src/ui/prompts/commonPrompts.ts
index f4f29d5e5..b11abd978 100644
--- a/src/ui/prompts/commonPrompts.ts
+++ b/src/ui/prompts/commonPrompts.ts
@@ -2,6 +2,7 @@ import chalk from 'chalk'
 import { ListPrompt, Prompt } from './types'
 import { partition } from 'lodash'
 import inquirer from '../autocomplete'
+import { isValidKey, isRequired, maxLength } from '../../utils/validators'
 
 export const hintTextTransformer = (hint: string) =>
     (value: string, answers: unknown, { isFinal }: { isFinal: boolean }) => {
@@ -26,6 +27,17 @@ export const keyPrompt: Prompt = {
         }
         return
     },
+    validate: (value: string) => {
+        const requiredResult = isRequired('Key', value)
+        if (requiredResult !== true) {
+            return requiredResult
+        }
+        const maxLengthResult = maxLength('Key', value, 100)
+        if (maxLengthResult !== true) {
+            return maxLengthResult
+        }
+        return isValidKey('Key', value)
+    },
     type: 'input'
 }
 
@@ -34,6 +46,13 @@ export const namePrompt: Prompt = {
     message: 'Name',
     suffix: ':',
     transformer: hintTextTransformer('(Human readable name)'),
+    validate: (value: string) => {
+        const requiredResult = isRequired('Name', value)
+        if (requiredResult !== true) {
+            return requiredResult
+        }
+        return maxLength('Name', value, 100)
+    },
     type: 'input'
 }
 
diff --git a/src/ui/prompts/listPrompts/listOptionsPrompt.ts b/src/ui/prompts/listPrompts/listOptionsPrompt.ts
index c220bb8be..901c2d0a4 100644
--- a/src/ui/prompts/listPrompts/listOptionsPrompt.ts
+++ b/src/ui/prompts/listPrompts/listOptionsPrompt.ts
@@ -142,7 +142,7 @@ export abstract class ListOptionsPrompt<T> {
                 case 'continue':
                     break
                 case 'exit':
-                    return this.list.map((item) => item.value) as unknown as T[]
+                    return this.list.map((item) => item.value.item) as unknown as T[]
             }
         } catch (e) {
             if (e instanceof ZodError) {
diff --git a/src/ui/prompts/listPrompts/targetingListPrompt.ts b/src/ui/prompts/listPrompts/targetingListPrompt.ts
index c36ff397e..a4ce28e36 100644
--- a/src/ui/prompts/listPrompts/targetingListPrompt.ts
+++ b/src/ui/prompts/listPrompts/targetingListPrompt.ts
@@ -8,11 +8,12 @@ import {
     ExitPrompt,
     ReorderItemPrompt
 } from './promptOptions'
-import { servePrompt, audienceNamePrompt } from '../targetingPrompts'
+import { servePrompt } from '../targetingPrompts'
 import { Filters, UpdateTargetParams, Variation } from '../../../api/schemas'
 import { FilterListOptions } from './filterListPrompt'
 import Writer from '../../writer'
 import { renderRulesTree } from '../../targetingTree'
+import { namePrompt } from '../commonPrompts'
 
 export class TargetingListOptions extends ListOptionsPrompt<UpdateTargetParams> {
     itemType = 'Targeting Rule'
@@ -42,7 +43,7 @@ export class TargetingListOptions extends ListOptionsPrompt<UpdateTargetParams>
     }
 
     async promptAddItem(): Promise<ListOption<UpdateTargetParams>> {
-        const { name, serve } = await inquirer.prompt([audienceNamePrompt, servePrompt], {
+        const { name, serve } = await inquirer.prompt([namePrompt, servePrompt], {
             token: this.authToken,
             projectKey: this.projectKey,
             featureKey: this.featureKey
@@ -82,7 +83,7 @@ export class TargetingListOptions extends ListOptionsPrompt<UpdateTargetParams>
         const targetToEdit = targetListItem.item
 
         const promptsWithDefaults = [
-            { ...audienceNamePrompt, default: targetToEdit.audience.name },
+            { ...namePrompt, default: targetToEdit.audience.name },
             { ...servePrompt, default: targetToEdit.distribution[0]._variation }
         ]
 
diff --git a/src/ui/prompts/listPrompts/variablesListPrompt.ts b/src/ui/prompts/listPrompts/variablesListPrompt.ts
index a4957e000..5a3e9810e 100644
--- a/src/ui/prompts/listPrompts/variablesListPrompt.ts
+++ b/src/ui/prompts/listPrompts/variablesListPrompt.ts
@@ -1,7 +1,7 @@
 import { createVariablePrompts } from '../variablePrompts'
 import { ListOption, ListOptionsPrompt } from './listOptionsPrompt'
 import inquirer from 'inquirer'
-import { CreateVariableDto, CreateVariableParams, UpdateVariableDto, Variable } from '../../../api/schemas'
+import { CreateVariableDto, CreateVariableParams, UpdateVariableDto } from '../../../api/schemas'
 import { errorMap } from '../../../api/apiClient'
 
 export class VariableListOptions extends ListOptionsPrompt<CreateVariableParams> {
@@ -10,15 +10,12 @@ export class VariableListOptions extends ListOptionsPrompt<CreateVariableParams>
 
     variablePropertyPrompts = createVariablePrompts.filter((prompt) => prompt.name !== '_feature')
 
-    getVariablesListPrompt = (existingVariables?: Variable[]) => ({
+    getVariablesListPrompt = () => ({
         name: 'variables', 
         value: 'variables', 
         message: 'Manage variables',
         type: 'listOptions',
-        listOptionsPrompt: () => this.prompt(existingVariables?.map((variable, index) => ({
-            name: variable.name || variable.key,
-            value: { item: variable, id: index }
-        })))
+        listOptionsPrompt: () => this.prompt()
     })
  
     async promptAddItem(): Promise<ListOption<CreateVariableParams>> {
@@ -67,5 +64,4 @@ export class VariableListOptions extends ListOptionsPrompt<CreateVariableParams>
             value: { item: createVariable, id: index } 
         }))
     }
-    
 }
diff --git a/src/ui/prompts/listPrompts/variationsListPrompt.ts b/src/ui/prompts/listPrompts/variationsListPrompt.ts
index d1938a6c6..372fdd59f 100644
--- a/src/ui/prompts/listPrompts/variationsListPrompt.ts
+++ b/src/ui/prompts/listPrompts/variationsListPrompt.ts
@@ -2,6 +2,7 @@
 import { errorMap } from '../../../api/apiClient'
 import { CreateVariationDto, CreateVariationParams, Variable, Variation } from '../../../api/schemas'
 import inquirer from '../../autocomplete'
+import Writer from '../../writer'
 import { getVariationVariablesPrompts, staticCreateVariationPrompts } from '../variationPrompts'
 import { ListOption, ListOptionsPrompt } from './listOptionsPrompt'
 
@@ -11,9 +12,12 @@ export class VariationListOptions extends ListOptionsPrompt<CreateVariationParam
 
     featureVariables: Variable[] = []
 
-    getVariationListPrompt = (existingVariations?: Variation[], existingVariables?: Variable[]) => {
+    constructor(list: CreateVariationParams[], existingVariables: Variable[], writer: Writer) {
+        super(list, writer)
         this.featureVariables = existingVariables || []
+    }
 
+    getVariationListPrompt = () => {
         return {
             name: 'variations', 
             value: 'variations', 
@@ -22,12 +26,10 @@ export class VariationListOptions extends ListOptionsPrompt<CreateVariationParam
             previousReponseFields: ['variables'], // if variables were just created / updated, use the new variables
             listOptionsPrompt: (previousResponses?: Record<string, any>) => {
                 const newVariables = previousResponses?.variables
-                this.featureVariables = newVariables || this.featureVariables
-
-                return this.prompt(existingVariations?.map((variation, index) => ({
-                    name: variation.name || variation.key,
-                    value: { item: variation, id: index } 
-                })))
+                if (newVariables) {
+                    this.featureVariables = newVariables
+                }
+                return this.prompt()
             }
         }
     }
diff --git a/src/ui/prompts/targetingPrompts.ts b/src/ui/prompts/targetingPrompts.ts
index 35bfee544..a1637b7a0 100644
--- a/src/ui/prompts/targetingPrompts.ts
+++ b/src/ui/prompts/targetingPrompts.ts
@@ -1,16 +1,6 @@
 import { DataKeyType, filterTypes, userSubTypes } from '../../api/targeting'
+import { isRequired } from '../../utils/validators'
 import { variationChoices } from './variationPrompts'
-import { namePrompt } from './commonPrompts'
-
-export const audienceNamePrompt = {
-    ...namePrompt,
-    validate: (value: string) => {
-        if (value.length === 0) {
-            return 'Name cannot be empty'
-        }
-        return true
-    }
-}
 
 export const comparatorChoices = (input: Record<string, any>) => {
     if (input.subType === 'appVersion') {
@@ -53,6 +43,7 @@ export const filterValuesPrompt = {
     name: 'values',
     message: 'List of comma separated values for definition',
     suffix: ':',
+    validate: (input: string) => (isRequired('values', input)),
     type: 'input'
 }
 
diff --git a/src/utils/prompts.ts b/src/utils/prompts.ts
index 522a985fe..b4fe900a9 100644
--- a/src/utils/prompts.ts
+++ b/src/utils/prompts.ts
@@ -1,18 +1,6 @@
-import { ClassConstructor } from 'class-transformer'
 import { Prompt } from '../ui/prompts'
-import { ValidatorOptions, validateSync } from 'class-validator'
-import { reportValidationErrors } from './reportValidationErrors'
 import inquirer from '../ui/autocomplete'
 
-export function validateParams<ResourceType>(
-    paramClass: ClassConstructor<ResourceType>,
-    params: ResourceType,
-    validatorOptions?: ValidatorOptions
-){
-    const errors = validateSync(params as Record<string, unknown>, { ...validatorOptions })
-    reportValidationErrors(errors)
-}
-
 // Filter out prompts that already have values provided by flags
 export function filterPrompts(prompts: Prompt[], flags: Record<string, unknown>) {
     let filteredPrompts: Prompt[] = [ ...prompts ]
diff --git a/src/utils/reportValidationErrors.ts b/src/utils/reportValidationErrors.ts
index a6676c771..b3e946e37 100644
--- a/src/utils/reportValidationErrors.ts
+++ b/src/utils/reportValidationErrors.ts
@@ -1,6 +1,15 @@
 import { ValidationError } from 'class-validator'
 import { ZodError } from 'zod'
 import Writer from '../ui/writer'
+import { ValidatorOptions, validateSync } from 'class-validator'
+
+export function validateParams<ResourceType>(
+    params: ResourceType,
+    validatorOptions?: ValidatorOptions
+){
+    const errors = validateSync(params as Record<string, unknown>, { ...validatorOptions })
+    reportValidationErrors(errors)
+}
 
 export function reportValidationErrors(errors: ValidationError[]): void {
     if (errors.length) {
diff --git a/src/utils/validators.ts b/src/utils/validators.ts
new file mode 100644
index 000000000..f4a081e21
--- /dev/null
+++ b/src/utils/validators.ts
@@ -0,0 +1,20 @@
+export const isRequired = (inputName: string, value: string) => {
+    if (!value || value.trim().length === 0) {
+        return `${inputName} is required.`
+    }
+    return true
+}
+
+export const isValidKey = (inputName: string, value: string) => {
+    if (!/^[\w-.]+$/.test(value)) {
+        return `${inputName} can only contain letters, dashes, dots and underscores.`
+    }
+    return true
+}
+
+export const maxLength = (inputName: string, value: string, max: number) => {
+    if (value.length > max) {
+        return `${inputName} cannot be longer than ${max} characters.`
+    }
+    return true
+}
